"use client";

import { useEffect, useMemo, useState } from "react";
import { nip19 } from "nostr-tools";
import {
  loadNostrProfile,
  resolveEventFromRelays,
  shortenPubkey,
  type NostrProfile,
} from "@/lib/nostr";

function njump(bech32: string): string {
  return `https://njump.me/${bech32}`;
}

// Inline @mention chip: avatar + display name, resolved live from the author's
// kind:0 profile. Falls back to a shortened pubkey until (or unless) it loads.
export function NostrMention({ bech32 }: { bech32: string }) {
  const pubkey = useMemo(() => {
    try {
      const d = nip19.decode(bech32);
      if (d.type === "npub") return d.data as string;
      if (d.type === "nprofile") return (d.data as { pubkey: string }).pubkey;
    } catch {}
    return null;
  }, [bech32]);

  const [profile, setProfile] = useState<NostrProfile | null>(null);

  useEffect(() => {
    if (!pubkey) return;
    let cancelled = false;
    loadNostrProfile(pubkey)
      .then((p) => !cancelled && setProfile(p))
      .catch(() => {});
    return () => {
      cancelled = true;
    };
  }, [pubkey]);

  // Show the username; fall back to a shortened npub only when no profile.
  const npub = useMemo(() => {
    if (bech32.startsWith("npub")) return bech32;
    return pubkey ? nip19.npubEncode(pubkey) : bech32;
  }, [bech32, pubkey]);
  const name = profile?.name || profile?.displayName || shortenPubkey(npub);

  return (
    <a
      href={njump(bech32)}
      target="_blank"
      rel="noopener noreferrer"
      className="inline-flex items-center gap-1 align-middle text-primary hover:underline font-medium no-underline"
    >
      {profile?.picture && (
        <img
          src={profile.picture}
          alt=""
          className="w-5 h-5 rounded-full object-cover bg-surface-container-high inline-block"
          onError={(e) => {
            (e.target as HTMLImageElement).style.display = "none";
          }}
        />
      )}
      <span>@{name}</span>
    </a>
  );
}

// Compact author line used inside an embedded note.
function NoteAuthor({ pubkey }: { pubkey: string }) {
  const [profile, setProfile] = useState<NostrProfile | null>(null);
  useEffect(() => {
    let cancelled = false;
    loadNostrProfile(pubkey)
      .then((p) => !cancelled && setProfile(p))
      .catch(() => {});
    return () => {
      cancelled = true;
    };
  }, [pubkey]);
  const fallback = useMemo(() => {
    try {
      return shortenPubkey(nip19.npubEncode(pubkey));
    } catch {
      return shortenPubkey(pubkey);
    }
  }, [pubkey]);
  const name = profile?.name || profile?.displayName || fallback;
  return (
    <span className="flex items-center gap-2">
      {profile?.picture && (
        <img
          src={profile.picture}
          alt=""
          className="w-6 h-6 rounded-full object-cover bg-surface-container-high"
          onError={(e) => {
            (e.target as HTMLImageElement).style.display = "none";
          }}
        />
      )}
      <span className="font-semibold text-on-surface text-sm">{name}</span>
    </span>
  );
}

// Embedded referenced note (note/nevent/naddr). Renders as a bordered card.
// Uses span/block elements (not <div>) so it stays valid when the reference
// sits inside a markdown paragraph.
export function NostrNote({ bech32 }: { bech32: string }) {
  const [event, setEvent] = useState<any>(null);
  const [state, setState] = useState<"loading" | "done" | "error">("loading");

  useEffect(() => {
    let cancelled = false;
    setState("loading");
    resolveEventFromRelays(bech32)
      .then((ev) => {
        if (cancelled) return;
        if (ev) {
          setEvent(ev);
          setState("done");
        } else {
          setState("error");
        }
      })
      .catch(() => !cancelled && setState("error"));
    return () => {
      cancelled = true;
    };
  }, [bech32]);

  return (
    <span className="block my-4 rounded-xl border border-surface-container-high bg-surface-container-low p-4">
      {state === "loading" && (
        <span className="flex items-center gap-2 text-on-surface-variant text-sm">
          <span className="inline-block w-4 h-4 rounded-full border-2 border-primary/30 border-t-primary animate-spin" />
          Loading note…
        </span>
      )}
      {state === "error" && (
        <a
          href={njump(bech32)}
          target="_blank"
          rel="noopener noreferrer"
          className="text-primary hover:underline text-sm break-all"
        >
          View referenced note on njump.me
        </a>
      )}
      {state === "done" && event && (
        <span className="block">
          <span className="flex items-center justify-between mb-3">
            <NoteAuthor pubkey={event.pubkey} />
            <a
              href={njump(bech32)}
              target="_blank"
              rel="noopener noreferrer"
              className="text-xs text-on-surface-variant/60 hover:text-primary"
            >
              View note
            </a>
          </span>
          <span className="block whitespace-pre-wrap break-words text-on-surface-variant text-sm leading-relaxed">
            {(event.content || "").slice(0, 1000)}
            {(event.content || "").length > 1000 ? "…" : ""}
          </span>
        </span>
      )}
    </span>
  );
}

// Dispatches a `nostr:<bech32>` reference to the right embed by entity type.
export function NostrEntity({ bech32 }: { bech32: string }) {
  let type: string;
  try {
    type = nip19.decode(bech32).type;
  } catch {
    return <>nostr:{bech32}</>;
  }
  if (type === "npub" || type === "nprofile") return <NostrMention bech32={bech32} />;
  if (type === "note" || type === "nevent" || type === "naddr") return <NostrNote bech32={bech32} />;
  return <>nostr:{bech32}</>;
}
