import { SimplePool } from '@nostr/tools/pool'
import { ListFetcher, loadRelayList, RelayItem } from '@nostr/gadgets/lists'
import { setPool } from '@nostr/gadgets/global'
import { loadNostrUser, NostrUser } from '@nostr/gadgets/metadata'
import { decode } from '@nostr/tools/nip19'
import { queryProfile } from '@nostr/tools/nip05'
import type { WindowNostr } from '@nostr/tools/nip07'

export const pool = (((window as any).nostrSharedPool as SimplePool) || new SimplePool()) as SimplePool
;(window as any).nostrSharedPool = pool
setPool(pool as any)

const lrl = ((window as any).nostrSharedRelayListLoader || loadRelayList) as ListFetcher<RelayItem>
;(window as any).nostrSharedRelayListLoader = lrl

const lnu = ((window as any).nostrSharedMetadataLoader || loadNostrUser) as (req: {
  pubkey: string
  relays: string[]
}) => Promise<NostrUser>
;(window as any).nostrSharedMetadataLoader = lnu

export async function fetchNostrUser(pubkey: string, relays: string[]): Promise<NostrUser> {
  return await lnu({ pubkey, relays })
}

export async function getOutboxRelaysFor(pubkey: string): Promise<string[]> {
  let rl = await lrl(pubkey)
  return rl.items.filter(r => r.write).map(r => r.url)
}

export async function getInboxRelaysFor(pubkey: string): Promise<string[]> {
  let rl = await lrl(pubkey)
  return rl.items.filter(r => r.read).map(r => r.url)
}

export async function inputToPubkey(input: string): Promise<[string, string[]] | [undefined]> {
  try {
    const { type, data } = decode(input)
    if (type === 'nprofile') {
      return [data.pubkey, data.relays || []]
    } else if (type === 'npub') {
      return [data, []]
    }
  } catch (err) {
    if (input.match(/[0-9a-f]{64}/)) {
      return [input, []]
    } else if (input.match('.')) {
      let res = await queryProfile(input)
      if (!res) return [undefined]
      return [res.pubkey, res.relays || []]
    }
  }
  return [undefined]
}

export async function getWindowNostr(): Promise<WindowNostr> {
  const wn = (window as any).nostr
  if (!wn) {
    return new Promise<WindowNostr>((resolve, reject) => {
      try {
        let script = document.createElement('script')
        script.onload = () => resolve((window as any).nostr)
        script.src = 'https://cdn.jsdelivr.net/npm/window.nostr.js/dist/window.nostr.min.js'
        document.head.appendChild(script)
      } catch (err) {
        reject(err)
      }
    })
  }
  return wn
}
