import { auth } from "$lib/auth.svelte";
import { withJoin } from "$lib/join.svelte";
import { activeGroup } from "$lib/active.svelte";
import { publishForum } from "$lib/relay";
import { extractMentionPubkeys, buildPTagHints } from "$lib/mentions";
import { convertForumUrls } from "$lib/linkify";

let modalOpen = $state(false);
let iconized = $state(false);
let title = $state("");
let labels = $state<string[]>([]);
let content = $state("");
let publishing = $state(false);
let publishError = $state<string | null>(null);

export const draftState = {
  get modalOpen() {
    return modalOpen;
  },
  get iconized() {
    return iconized;
  },
  get title() {
    return title;
  },
  set title(v: string) {
    title = v;
  },
  get labels() {
    return labels;
  },
  get content() {
    return content;
  },
  set content(v: string) {
    content = v;
  },
  get publishing() {
    return publishing;
  },
  get publishError() {
    return publishError;
  },
  get hasDraft() {
    return (
      title.trim().length > 0 || content.trim().length > 0 || labels.length > 0
    );
  },
};

export function openDraft() {
  modalOpen = true;
  iconized = false;
  publishError = null;
}

export function iconizeDraft() {
  // If nothing was entered, fully close instead of showing the resume pill
  if (!draftState.hasDraft) {
    discardDraft();
    return;
  }
  modalOpen = false;
  iconized = true;
}

export function resumeDraft() {
  modalOpen = true;
  iconized = false;
}

export function discardDraft() {
  title = "";
  labels = [];
  content = "";
  publishError = null;
  modalOpen = false;
  iconized = false;
}

export function addLabel(l: string) {
  const v = l.trim();
  if (!v) return;
  if (labels.includes(v)) return;
  labels = [...labels, v];
}

export function removeLabel(l: string) {
  labels = labels.filter((x) => x !== l);
}

export async function publishDraft(): Promise<{
  ok: boolean;
  threadId?: string;
}> {
  if (!auth.signer) {
    publishError = "Not logged in";
    return { ok: false };
  }
  const t = title.trim();
  if (!t || !content.trim()) {
    publishError = "Title and content are required";
    return { ok: false };
  }
  const c = convertForumUrls(content.trim());
  const groupId = activeGroup.id;
  if (!groupId) {
    publishError = "No room selected";
    return { ok: false };
  }

  publishing = true;
  publishError = null;
  let threadId: string | undefined;

  const ownPubkey = auth.user?.pubkey;
  const mentionPubkeys = extractMentionPubkeys(c).filter(
    (pk) => pk !== ownPubkey,
  );
  const hints = await buildPTagHints(mentionPubkeys);

  try {
    const success = await withJoin(groupId, async () => {
      const tags: string[][] = [
        ["h", groupId],
        ["title", t],
      ];
      for (const l of labels) tags.push(["t", l]);
      for (const pk of mentionPubkeys) {
        const hint = hints.get(pk);
        tags.push(hint ? ["p", pk, hint] : ["p", pk]);
      }

      const event = await auth.signer!.signEvent({
        kind: 11,
        created_at: Math.floor(Date.now() / 1000),
        tags,
        content: c,
      });

      const timeout = new Promise<never>((_, reject) =>
        setTimeout(
          () => reject(new Error("Relay did not respond in time")),
          8000,
        ),
      );
      await Promise.race([Promise.all(publishForum(event)), timeout]);

      threadId = event.id;
    });

    if (success && threadId) {
      discardDraft();
      return { ok: true, threadId };
    }
    return { ok: false };
  } catch (e) {
    publishError = e instanceof Error ? e.message : "Failed to publish";
    return { ok: false };
  } finally {
    publishing = false;
  }
}
