import { generateSecretKey, getPublicKey as getPubKeyFromSecret } from "nostr-tools/pure";

declare global {
  interface Window {
    nostr?: {
      getPublicKey(): Promise<string>;
      signEvent(event: any): Promise<any>;
      getRelays?(): Promise<Record<string, { read: boolean; write: boolean }>>;
    };
  }
}

export type BunkerSignerInterface = {
  getPublicKey(): Promise<string>;
  signEvent(event: any): Promise<any>;
  close(): Promise<void>;
};

export function hasNostrExtension(): boolean {
  return typeof window !== "undefined" && !!window.nostr;
}

export async function getPublicKey(): Promise<string> {
  if (!window.nostr) throw new Error("No Nostr extension found");
  return window.nostr.getPublicKey();
}

export async function signEvent(event: any): Promise<any> {
  if (!window.nostr) throw new Error("No Nostr extension found");
  return window.nostr.signEvent(event);
}

export function createAuthEvent(pubkey: string, challenge: string) {
  return {
    kind: 22242,
    created_at: Math.floor(Date.now() / 1000),
    tags: [
      ["relay", ""],
      ["challenge", challenge],
    ],
    content: "",
    pubkey,
  };
}

export function shortenPubkey(pubkey: string): string {
  if (!pubkey) return "";
  return `${pubkey.slice(0, 8)}...${pubkey.slice(-8)}`;
}

export interface NostrProfile {
  name?: string;
  picture?: string;
  about?: string;
  nip05?: string;
  displayName?: string;
}

const DEFAULT_RELAYS = [
  "wss://relay.damus.io",
  "wss://nos.lol",
  "wss://relay.nostr.band",
];

export async function publishEvent(signedEvent: any): Promise<void> {
  const { SimplePool } = await import("nostr-tools/pool");
  let relayUrls: string[] = DEFAULT_RELAYS;
  try {
    if (window.nostr?.getRelays) {
      const ext = await window.nostr.getRelays();
      const write = Object.entries(ext)
        .filter(([, p]) => (p as any).write)
        .map(([url]) => url);
      if (write.length > 0) relayUrls = write;
    }
  } catch {}
  const pool = new SimplePool();
  try {
    await Promise.allSettled(pool.publish(relayUrls, signedEvent));
  } finally {
    pool.close(relayUrls);
  }
}

export async function fetchNostrProfile(
  pubkey: string,
  relayUrls: string[] = DEFAULT_RELAYS
): Promise<NostrProfile> {
  const { SimplePool } = await import("nostr-tools/pool");
  const pool = new SimplePool();

  try {
    const event = await pool.get(relayUrls, {
      kinds: [0],
      authors: [pubkey],
    });

    if (!event?.content) return {};

    const meta = JSON.parse(event.content);
    return {
      name: meta.name || meta.display_name,
      displayName: meta.display_name,
      picture: meta.picture,
      about: meta.about,
      nip05: meta.nip05,
    };
  } catch {
    return {};
  } finally {
    pool.close(relayUrls);
  }
}

// NIP-46: External signer (bunker:// URI)
export async function createBunkerSigner(
  input: string
): Promise<{ signer: BunkerSignerInterface; pubkey: string }> {
  const { BunkerSigner, parseBunkerInput } = await import("nostr-tools/nip46");
  const bp = await parseBunkerInput(input);
  if (!bp) throw new Error("Invalid bunker URI or NIP-05 identifier");
  const clientSecretKey = generateSecretKey();
  const signer = BunkerSigner.fromBunker(clientSecretKey, bp);
  await signer.connect();
  const pubkey = await signer.getPublicKey();
  return { signer, pubkey };
}

// NIP-46: Generate a nostrconnect:// URI for QR display
export async function generateNostrConnectSetup(
  relayUrls: string[] = DEFAULT_RELAYS.slice(0, 2)
): Promise<{ uri: string; clientSecretKey: Uint8Array }> {
  const { createNostrConnectURI } = await import("nostr-tools/nip46");
  const clientSecretKey = generateSecretKey();
  const clientPubkey = getPubKeyFromSecret(clientSecretKey);
  const secretBytes = crypto.getRandomValues(new Uint8Array(8));
  const secret = Array.from(secretBytes)
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");
  const uri = createNostrConnectURI({
    clientPubkey,
    relays: relayUrls,
    secret,
    name: "Belgian Bitcoin Embassy",
  });
  return { uri, clientSecretKey };
}

// NIP-46: Wait for a remote signer to connect via nostrconnect:// URI
export async function waitForNostrConnectSigner(
  clientSecretKey: Uint8Array,
  uri: string,
  signal?: AbortSignal
): Promise<{ signer: BunkerSignerInterface; pubkey: string }> {
  const { BunkerSigner } = await import("nostr-tools/nip46");
  const signer = await BunkerSigner.fromURI(clientSecretKey, uri, {}, signal);
  const pubkey = await signer.getPublicKey();
  return { signer, pubkey };
}
