import {
  Action,
  ActionPanel,
  AI,
  Clipboard,
  Detail,
  Form,
  Icon,
  showToast,
  Toast,
  useNavigation,
} from "@raycast/api";
import { getSelectedTextSafely } from "./selection";
import { useEffect, useMemo, useRef, useState } from "react";
import {
  CREATIVITY_OPTIONS,
  DEFAULT_MODEL,
  getLastUsedModel,
  MODEL_OPTIONS,
  setLastUsedModel,
} from "./ai";
import { getPreferences } from "./preferences";
import {
  buildDisclosureContent,
  buildReplyPrompt,
  composeReplyEmail,
  type DisclosureContent,
  GREETING_OPTIONS,
  loadReplyDefaults,
  plainTextToHtmlEmail,
  saveReplyDefaults,
  SIGN_OFF_OPTIONS,
} from "./reply";
import {
  createSession,
  getActiveSessionId,
  getSession,
  listSessions,
  setActiveSession,
  updateSessionMapping,
} from "./sessions";
import type { Creativity } from "./summarize";
import type { EntityType, VelumSession } from "./types";
import {
  markdownCodeBlock,
  mappingDetailTable,
  NEW_SESSION_ID,
  sessionSubtitle,
} from "./ui";
import {
  getEntityTypes,
  localDepseudonymize,
  normalizePseudonymizeResponse,
  pseudonymize,
} from "./velum";

type FormValues = {
  text: string;
  sessionId: string;
  entityTypes: string[];
  instructions: string;
};

export default function Command() {
  const preferences = getPreferences();
  const [text, setText] = useState("");
  const [sessions, setSessions] = useState<VelumSession[]>([]);
  const [activeSessionId, setActiveSessionId] = useState<string>();
  const [entityTypes, setEntityTypes] = useState<EntityType[]>([]);
  const [selectedEntityTypes, setSelectedEntityTypes] = useState<string[]>([]);
  const [greeting, setGreeting] = useState("Lieber");
  const [signOff, setSignOff] = useState("Alles Liebe,");
  const [userFullName, setUserFullName] = useState(preferences.userFullName);
  const [model, setModel] = useState<string>(DEFAULT_MODEL);
  const [creativity, setCreativity] = useState<Creativity>("medium");
  const [disclosure, setDisclosure] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const { push } = useNavigation();

  useEffect(() => {
    async function load() {
      const [loadedSessions, activeId, defaults, lastModel] = await Promise.all(
        [
          listSessions(),
          getActiveSessionId(),
          loadReplyDefaults(),
          getLastUsedModel(),
        ],
      );
      setSessions(loadedSessions);
      setActiveSessionId(activeId);
      setModel(lastModel);

      if (defaults.greeting) setGreeting(defaults.greeting);
      if (defaults.signOff) setSignOff(defaults.signOff);
      if (defaults.creativity) setCreativity(defaults.creativity as Creativity);
      if (typeof defaults.disclosure === "boolean")
        setDisclosure(defaults.disclosure);

      const selection = await getSelectedTextSafely();
      if (selection && selection.trim()) {
        setText(selection);
      }

      try {
        const loadedEntityTypes = await getEntityTypes();
        setEntityTypes(loadedEntityTypes);
        setSelectedEntityTypes(loadedEntityTypes);
      } catch {
        setEntityTypes([]);
      } finally {
        setIsLoading(false);
      }
    }
    load();
  }, [preferences.userFullName]);

  function persist(
    overrides: Partial<{
      greeting: string;
      signOff: string;
      creativity: Creativity;
      disclosure: boolean;
    }>,
  ) {
    saveReplyDefaults({
      greeting: overrides.greeting ?? greeting,
      signOff: overrides.signOff ?? signOff,
      creativity: overrides.creativity ?? creativity,
      disclosure: overrides.disclosure ?? disclosure,
    }).catch(() => {
      // Best-effort persistence.
    });
  }

  const defaultSessionId = useMemo(
    () => activeSessionId || sessions[0]?.id || NEW_SESSION_ID,
    [activeSessionId, sessions],
  );

  async function loadSelectedText() {
    const selected = await getSelectedTextSafely();
    if (!selected) {
      await showToast({
        style: Toast.Style.Failure,
        title: "Kein markierter Text gefunden",
      });
      return;
    }
    setText(selected);
  }

  async function loadClipboardText() {
    const clipboardText = await Clipboard.readText();
    if (!clipboardText) {
      await showToast({
        style: Toast.Style.Failure,
        title: "Zwischenablage enthält keinen Text",
      });
      return;
    }
    setText(clipboardText);
  }

  async function handleSubmit(values: FormValues) {
    const input = values.text.trim();
    if (!input) {
      await showToast({
        style: Toast.Style.Failure,
        title: "Email zum Beantworten eingeben",
      });
      return;
    }
    if (!userFullName.trim()) {
      await showToast({
        style: Toast.Style.Failure,
        title: "Eigener Name fehlt",
        message: "Trage deinen Namen für die Signatur ein.",
      });
      return;
    }

    void setLastUsedModel(model);
    await saveReplyDefaults({
      greeting,
      signOff,
      creativity,
      disclosure,
    });

    const toast = await showToast({
      style: Toast.Style.Animated,
      title: "Pseudonymisiere…",
    });

    try {
      const session =
        values.sessionId === NEW_SESSION_ID
          ? await createSession()
          : ((await getSession(values.sessionId)) ?? (await createSession()));
      await setActiveSession(session.id);

      const rawResult = await pseudonymize(
        input,
        session.mapping,
        values.entityTypes,
      );
      const pseudoResult = normalizePseudonymizeResponse(rawResult);
      const updatedSession = await updateSessionMapping(
        session.id,
        pseudoResult.mapping,
        pseudoResult.selected_entity_types,
      );

      toast.style = Toast.Style.Success;
      toast.title = "Pseudonymisiert";
      toast.message = `${pseudoResult.entity_count} Zuordnungen`;

      push(
        <ConfirmReply
          session={updatedSession}
          pseudonymizedText={pseudoResult.pseudonymized_text}
          model={model}
          creativity={creativity}
          greeting={greeting}
          signOff={signOff}
          userFullName={userFullName}
          instructions={values.instructions}
          disclosure={disclosure}
        />,
      );
    } catch (error) {
      toast.style = Toast.Style.Failure;
      toast.title = "Pseudonymisierung fehlgeschlagen";
      toast.message = error instanceof Error ? error.message : String(error);
    }
  }

  return (
    <Form
      isLoading={isLoading}
      actions={
        <ActionPanel>
          <Action.SubmitForm
            title="Antwort generieren"
            icon={Icon.Reply}
            onSubmit={handleSubmit}
          />
          <Action
            title="Markierten Text übernehmen"
            icon={Icon.TextSelection}
            onAction={loadSelectedText}
          />
          <Action
            title="Zwischenablage übernehmen"
            icon={Icon.Clipboard}
            onAction={loadClipboardText}
          />
        </ActionPanel>
      }
    >
      <Form.TextArea
        id="text"
        title="Email / Mailverlauf"
        value={text}
        onChange={setText}
        placeholder="Email oder Mailverlauf einfügen oder laden"
      />
      <Form.Dropdown
        id="greeting"
        title="Anrede"
        value={greeting}
        onChange={(v) => {
          setGreeting(v);
          persist({ greeting: v });
        }}
      >
        {GREETING_OPTIONS.map((option) => (
          <Form.Dropdown.Item
            key={option.value}
            value={option.value}
            title={option.title}
          />
        ))}
      </Form.Dropdown>
      <Form.Dropdown
        id="signOff"
        title="Grußformel"
        value={signOff}
        onChange={(v) => {
          setSignOff(v);
          persist({ signOff: v });
        }}
      >
        {SIGN_OFF_OPTIONS.map((option) => (
          <Form.Dropdown.Item
            key={option.value}
            value={option.value}
            title={option.title}
          />
        ))}
      </Form.Dropdown>
      <Form.TextField
        id="userFullName"
        title="Eigener Name"
        value={userFullName}
        onChange={setUserFullName}
        info="Wird aus den Extension-Einstellungen vorbefüllt und nur für diesen Aufruf überschrieben."
        placeholder="Wird unter die Grußformel gesetzt"
      />
      <Form.TextArea
        id="instructions"
        title="Zusätzliche Anweisungen"
        placeholder="Optional: Tonfall, Inhalte, Termine, …"
      />
      <Form.Checkbox
        id="disclosure"
        label="Maskierungs-Hinweis am Ende anfügen"
        value={disclosure}
        onChange={(v) => {
          setDisclosure(v);
          persist({ disclosure: v });
        }}
        info="Listet am Ende der Email auf, welche Originalbegriffe vor dem KI-Aufruf lokal durch Platzhalter ersetzt wurden."
      />
      <Form.Separator />
      <Form.Dropdown
        id="sessionId"
        title="Sitzung"
        defaultValue={defaultSessionId}
      >
        <Form.Dropdown.Item
          value={NEW_SESSION_ID}
          title="Neue Sitzung"
          icon={Icon.Plus}
        />
        {sessions.map((session) => (
          <Form.Dropdown.Item
            key={session.id}
            value={session.id}
            title={session.name}
            icon={
              session.id === activeSessionId ? Icon.CheckCircle : Icon.Circle
            }
          />
        ))}
      </Form.Dropdown>
      {entityTypes.length > 0 ? (
        <Form.TagPicker
          id="entityTypes"
          title="Entitätstypen"
          value={selectedEntityTypes}
          onChange={setSelectedEntityTypes}
        >
          {entityTypes.map((entityType) => (
            <Form.TagPicker.Item
              key={entityType}
              value={entityType}
              title={entityType}
            />
          ))}
        </Form.TagPicker>
      ) : null}
      <Form.Dropdown
        id="model"
        title="KI-Modell"
        value={model}
        onChange={setModel}
      >
        {MODEL_OPTIONS.map((option) => (
          <Form.Dropdown.Item
            key={option.value}
            value={option.value}
            title={option.title}
          />
        ))}
      </Form.Dropdown>
      <Form.Dropdown
        id="creativity"
        title="Kreativität"
        value={creativity}
        onChange={(v) => {
          const next = v as Creativity;
          setCreativity(next);
          persist({ creativity: next });
        }}
      >
        {CREATIVITY_OPTIONS.map((value) => (
          <Form.Dropdown.Item key={value} value={value} title={value} />
        ))}
      </Form.Dropdown>
    </Form>
  );
}

type StageProps = {
  session: VelumSession;
  pseudonymizedText: string;
  model: string;
  creativity: Creativity;
  greeting: string;
  signOff: string;
  userFullName: string;
  instructions: string;
  disclosure: boolean;
};

function ConfirmReply(props: StageProps) {
  const [editedText, setEditedText] = useState(props.pseudonymizedText);
  const [editedInstructions, setEditedInstructions] = useState(
    props.instructions,
  );
  const [greeting, setGreeting] = useState(props.greeting);
  const [signOff, setSignOff] = useState(props.signOff);
  const [userFullName, setUserFullName] = useState(props.userFullName);
  const [disclosure, setDisclosure] = useState(props.disclosure);
  const { push } = useNavigation();

  async function handleSubmit() {
    if (!editedText.trim()) {
      await showToast({
        style: Toast.Style.Failure,
        title: "Pseudonymisierter Text ist leer",
      });
      return;
    }
    if (!userFullName.trim()) {
      await showToast({
        style: Toast.Style.Failure,
        title: "Eigener Name fehlt",
        message: "Trage deinen Namen für die Signatur ein.",
      });
      return;
    }

    await saveReplyDefaults({
      greeting,
      signOff,
      creativity: props.creativity,
      disclosure,
    });

    push(
      <ReplyResult
        session={props.session}
        pseudonymizedText={editedText}
        model={props.model}
        creativity={props.creativity}
        greeting={greeting}
        signOff={signOff}
        userFullName={userFullName}
        instructions={editedInstructions}
        disclosure={disclosure}
      />,
    );
  }

  return (
    <Form
      actions={
        <ActionPanel>
          <Action.SubmitForm
            title="An KI senden"
            icon={Icon.Wand}
            onSubmit={handleSubmit}
          />
          <Action.CopyToClipboard
            title="Pseudonymisierten Text kopieren"
            content={editedText}
          />
        </ActionPanel>
      }
    >
      <Form.Description
        title="Bestätigen"
        text={`Prüfe den pseudonymisierten Text vor dem KI-Aufruf. Die KI verfasst die Anrede mit dem passenden Platzhalter selbst — nur die Signatur wird lokal angefügt. Sitzung: ${props.session.name} · ${Object.keys(props.session.mapping).length} Zuordnungen.`}
      />
      <Form.TextArea
        id="pseudonymizedText"
        title="Pseudonymisierter Text"
        value={editedText}
        onChange={setEditedText}
      />
      <Form.Dropdown
        id="greeting"
        title="Anrede"
        value={greeting}
        onChange={(v) => {
          setGreeting(v);
          saveReplyDefaults({
            greeting: v,
            signOff,
            creativity: props.creativity,
            disclosure,
          }).catch(() => {});
        }}
      >
        {GREETING_OPTIONS.map((option) => (
          <Form.Dropdown.Item
            key={option.value}
            value={option.value}
            title={option.title}
          />
        ))}
      </Form.Dropdown>
      <Form.Dropdown
        id="signOff"
        title="Grußformel"
        value={signOff}
        onChange={(v) => {
          setSignOff(v);
          saveReplyDefaults({
            greeting,
            signOff: v,
            creativity: props.creativity,
            disclosure,
          }).catch(() => {});
        }}
      >
        {SIGN_OFF_OPTIONS.map((option) => (
          <Form.Dropdown.Item
            key={option.value}
            value={option.value}
            title={option.title}
          />
        ))}
      </Form.Dropdown>
      <Form.TextField
        id="userFullName"
        title="Eigener Name"
        value={userFullName}
        onChange={setUserFullName}
      />
      <Form.TextArea
        id="instructions"
        title="Zusätzliche Anweisungen"
        value={editedInstructions}
        onChange={setEditedInstructions}
        placeholder="Optional"
      />
      <Form.Checkbox
        id="disclosure"
        label="Maskierungs-Hinweis am Ende anfügen"
        value={disclosure}
        onChange={(v) => {
          setDisclosure(v);
          saveReplyDefaults({
            greeting,
            signOff,
            creativity: props.creativity,
            disclosure: v,
          }).catch(() => {});
        }}
      />
      <Form.Separator />
      <Form.Description
        title="Zuordnung"
        text={mappingDescriptionText(props.session)}
      />
    </Form>
  );
}

function mappingDescriptionText(session: VelumSession): string {
  const entries = Object.entries(session.mapping).sort(([a], [b]) =>
    a.localeCompare(b),
  );
  if (entries.length === 0) {
    return "Keine Einträge — nichts wurde pseudonymisiert.";
  }
  return entries
    .map(([placeholder, entry]) => `${placeholder} → ${entry.original}`)
    .join("\n");
}

type Phase = "drafting" | "restoring" | "done" | "error";

function ReplyResult(props: StageProps) {
  const [aiBody, setAiBody] = useState("");
  const [restoredEmail, setRestoredEmail] = useState<string | null>(null);
  const [disclosureContent, setDisclosureContent] =
    useState<DisclosureContent | null>(null);
  const [phase, setPhase] = useState<Phase>("drafting");
  const [error, setError] = useState<string | null>(null);
  const controllerRef = useRef<AbortController | null>(null);

  useEffect(() => {
    const controller = new AbortController();
    controllerRef.current = controller;
    let cancelled = false;

    async function run() {
      const toast = await showToast({
        style: Toast.Style.Animated,
        title: "Verfasse Antwort…",
      });

      try {
        const prompt = buildReplyPrompt({
          pseudonymizedText: props.pseudonymizedText,
          greeting: props.greeting,
          instructions: props.instructions,
        });
        const stream = AI.ask(prompt, {
          model: props.model as AI.Model,
          creativity: props.creativity,
          signal: controller.signal,
        });
        stream.on("data", (chunk) => {
          if (cancelled) return;
          setAiBody((prev) => prev + chunk);
        });
        const aiText = await stream;
        if (cancelled) return;

        toast.title = "Stelle wieder her…";
        setPhase("restoring");

        const composed = composeReplyEmail({
          body: aiText,
          signOff: props.signOff,
          userFullName: props.userFullName,
        });

        const restoreResult = localDepseudonymize(
          composed,
          props.session.mapping,
        );
        if (cancelled) return;

        const disclosure = props.disclosure
          ? buildDisclosureContent(
              props.pseudonymizedText,
              props.session.mapping,
            )
          : null;

        setRestoredEmail(restoreResult.original_text);
        setDisclosureContent(disclosure);
        setPhase("done");

        toast.style = Toast.Style.Success;
        toast.title = "Fertig";
        toast.message = `${restoreResult.replacements_made} Ersetzungen`;
      } catch (err) {
        if (cancelled || controller.signal.aborted) return;
        const message = err instanceof Error ? err.message : String(err);
        setError(message);
        setPhase("error");
        toast.style = Toast.Style.Failure;
        toast.title = "Antwort fehlgeschlagen";
        toast.message = message;
      }
    }

    run();

    return () => {
      cancelled = true;
      controller.abort();
    };
  }, [
    props.pseudonymizedText,
    props.model,
    props.creativity,
    props.instructions,
    props.session.mapping,
    props.greeting,
    props.signOff,
    props.userFullName,
    props.disclosure,
  ]);

  const phaseLabel =
    phase === "drafting"
      ? "KI verfasst Antwort …"
      : phase === "restoring"
        ? "Platzhalter werden ersetzt …"
        : phase === "error"
          ? "Fehler"
          : "Fertig";

  const finalEmailText = restoredEmail
    ? disclosureContent
      ? `${restoredEmail.trimEnd()}\n\n${disclosureContent.text}`
      : restoredEmail
    : null;

  const previewBody =
    finalEmailText ??
    composeReplyEmail({
      body: aiBody || "_Noch keine Inhalte — warte auf das Modell …_",
      signOff: props.signOff,
      userFullName: props.userFullName,
    });

  const finalEmailHtml = restoredEmail
    ? disclosureContent
      ? `${plainTextToHtmlEmail(restoredEmail)}\n${disclosureContent.html}`
      : plainTextToHtmlEmail(restoredEmail)
    : null;

  const markdown = [
    "# Email-Antwort",
    sessionSubtitle(props.session),
    `*Status:* ${phaseLabel}`,
    "",
    "## Generierte Antwort (zum Versenden)",
    markdownCodeBlock(previewBody),
    "",
    "---",
    "",
    "## Pseudonymisierte Eingabe",
    markdownCodeBlock(props.pseudonymizedText),
    "",
    "## Pseudonymisierter KI-Body",
    aiBody.trim()
      ? markdownCodeBlock(aiBody)
      : "_Noch nichts vom Modell empfangen._",
    "",
    "## Zuordnung",
    mappingDetailTable(props.session.mapping),
    error ? `\n> Fehler: ${error}` : "",
  ].join("\n");

  const isLoading = phase === "drafting" || phase === "restoring";

  return (
    <Detail
      isLoading={isLoading}
      markdown={markdown}
      actions={
        <ActionPanel>
          {finalEmailText && finalEmailHtml ? (
            <>
              <Action.CopyToClipboard
                title="Antwort kopieren (HTML)"
                content={{
                  html: finalEmailHtml,
                  text: finalEmailText,
                }}
              />
              <Action
                title="Antwort einfügen (HTML)"
                icon={Icon.TextCursor}
                onAction={() =>
                  Clipboard.paste({
                    html: finalEmailHtml,
                    text: finalEmailText,
                  })
                }
              />
              <Action.CopyToClipboard
                title="Antwort kopieren (Klartext)"
                content={finalEmailText}
              />
            </>
          ) : null}
          {aiBody ? (
            <Action.CopyToClipboard
              title="Pseudonymisierten KI-Body kopieren"
              content={aiBody}
            />
          ) : null}
          <Action.CopyToClipboard
            title="Pseudonymisierte Eingabe kopieren"
            content={props.pseudonymizedText}
          />
        </ActionPanel>
      }
    />
  );
}
