import { LRUCache } from 'lru-cache'
import { nip19 } from 'nostr-tools'

export function formatPubkey(pubkey: string) {
  const npub = pubkeyToNpub(pubkey)
  if (npub) {
    return formatNpub(npub)
  }
  return pubkey.slice(0, 4) + '...' + pubkey.slice(-4)
}

export function formatNpub(npub: string, length = 12) {
  if (length < 12) {
    length = 12
  }

  if (length >= 63) {
    return npub
  }

  const prefixLength = Math.floor((length - 5) / 2) + 5
  const suffixLength = length - prefixLength
  return npub.slice(0, prefixLength) + '...' + npub.slice(-suffixLength)
}

export function formatUserId(userId: string) {
  if (userId.startsWith('npub1')) {
    return formatNpub(userId)
  }
  return formatPubkey(userId)
}

export function pubkeyToNpub(pubkey: string) {
  try {
    return nip19.npubEncode(pubkey)
  } catch {
    return null
  }
}

export function userIdToPubkey(userId: string, throwOnInvalid = false): string {
  if (userId.startsWith('npub1') || userId.startsWith('nprofile1')) {
    try {
      const { type, data } = nip19.decode(userId)
      if (type === 'npub') {
        return data
      } else if (type === 'nprofile') {
        return data.pubkey
      }
    } catch (error) {
      if (throwOnInvalid) {
        throw new Error('Invalid id')
      }
      console.error('Error decoding userId:', userId, 'error:', error)
    }
  }
  return userId
}

export function isValidPubkey(pubkey: string) {
  return /^[0-9a-f]{64}$/.test(pubkey)
}

const pubkeyImageCache = new LRUCache<string, string>({ max: 1000 })
export function generateImageByPubkey(pubkey: string): string {
  if (pubkeyImageCache.has(pubkey)) {
    return pubkeyImageCache.get(pubkey)!
  }

  const paddedPubkey = pubkey.padEnd(2, '0')

  // Split into 3 parts for colors and the rest for control points
  const colors: string[] = []
  const controlPoints: string[] = []
  for (let i = 0; i < 11; i++) {
    const part = paddedPubkey.slice(i * 6, (i + 1) * 6)
    if (i < 3) {
      colors.push(`#${part}`)
    } else {
      controlPoints.push(part)
    }
  }

  // Generate SVG with multiple radial gradients
  const gradients = controlPoints
    .map((point, index) => {
      const cx = parseInt(point.slice(0, 2), 16) % 100
      const cy = parseInt(point.slice(2, 4), 16) % 100
      const r = (parseInt(point.slice(4, 6), 16) % 35) + 30
      const c = colors[index % (colors.length - 1)]

      return `
        <radialGradient id="grad${index}-${pubkey}" cx="${cx}%" cy="${cy}%" r="${r}%">
          <stop offset="0%" style="stop-color:${c};stop-opacity:1" />
          <stop offset="100%" style="stop-color:${c};stop-opacity:0" />
        </radialGradient>
        <rect width="100%" height="100%" fill="url(#grad${index}-${pubkey})" />
      `
    })
    .join('')

  const image = `
    <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
      <rect width="100%" height="100%" fill="${colors[2]}" fill-opacity="0.3" />
      ${gradients}
    </svg>
  `
  const imageData = `data:image/svg+xml;base64,${btoa(image)}`

  pubkeyImageCache.set(pubkey, imageData)

  return imageData
}
