import { useEffect, useMemo, useState } from "react";
import { Link } from "react-router-dom";
import { Badge, Button, EmptyState, Input, Select, Textarea } from "../ui";
import { useData, useRepos } from "../../data/DataContext";
import { findPersonaAnalyzeJob, useJobLive } from "../../data/JobLiveContext";
import type { Persona, StyleDimKey, ThreadsAccount } from "../../domain/types";
import { newId } from "../../lib/id";
import { useI18n } from "../../i18n/I18nContext";
import { jobStatusLabel, jobTemplateLabel } from "../../lib/jobLabels";
import {
  DIM_ORDER,
  buildPersonaPromptBlock,
  createEmptyPersona,
  isPersonaReady,
  markReady,
  serializeDraftText,
  toneOf,
} from "../../lib/personaPrompt";

type AnalyzeMode = "account" | "text";
type DetailTab = "overview" | "analyze" | "fingerprint" | "preview";

export function PersonaWorkbench() {
  const repos = useRepos();
  const { refresh, tick } = useData();
  const { jobs: liveJobs, reload: reloadJobs, revision: jobRevision } = useJobLive();
  const { t } = useI18n();

  const [personas, setPersonas] = useState<Persona[]>([]);
  const [accounts, setAccounts] = useState<ThreadsAccount[]>([]);
  const [activeId, setActiveId] = useState("");
  const [selectedId, setSelectedId] = useState("");
  const [detailTab, setDetailTab] = useState<DetailTab>("overview");
  const [analyzeMode, setAnalyzeMode] = useState<AnalyzeMode>("account");
  const [benchmarkUsername, setBenchmarkUsername] = useState("");
  const [refText, setRefText] = useState("");
  const [sourceLabel, setSourceLabel] = useState("");
  const [busy, setBusy] = useState("");
  const [message, setMessage] = useState("");
  const [loadError, setLoadError] = useState("");
  const [previewPost, setPreviewPost] = useState("");
  const [previewReply, setPreviewReply] = useState("");
  const [previewTopic, setPreviewTopic] = useState("");
  const [previewTopicSource, setPreviewTopicSource] = useState("");
  const [previewNotes, setPreviewNotes] = useState("");
  const [promptPreview, setPromptPreview] = useState("");
  const [showPrompt, setShowPrompt] = useState(false);
  /** mobile: list vs detail */
  const [mobileShowDetail, setMobileShowDetail] = useState(false);

  const selected = useMemo(
    () => personas.find((p) => p.id === selectedId) || personas[0],
    [personas, selectedId],
  );

  const analyzeJob = useMemo(
    () => findPersonaAnalyzeJob(liveJobs, selected?.id),
    [liveJobs, selected?.id],
  );

  function statusLabel(status: string): string {
    if (status === "ready") return t("persona.statusReady");
    if (status === "analyzing") return t("persona.statusAnalyzing");
    return t("persona.statusPending");
  }

  async function load() {
    try {
      const [list, active, accList] = await Promise.all([
        repos.personas.list(),
        repos.personas.getActiveId(),
        repos.accounts.list(),
      ]);
      setPersonas(list);
      setAccounts(accList);
      setActiveId(active);
      setSelectedId((cur) => {
        if (cur && list.some((p) => p.id === cur)) return cur;
        return active || list[0]?.id || "";
      });
      setLoadError("");
    } catch (e) {
      // 這裡不能借用 message：它同時被 job 進度用，下一次輪詢就會把錯誤蓋掉。
      setLoadError(e instanceof Error ? e.message : t("persona.loadFail"));
    }
  }

  useEffect(() => {
    void load();
  }, [tick, repos.personas, repos.accounts]); // eslint-disable-line react-hooks/exhaustive-deps

  const anyAnalyzing = personas.some((p) => p.status === "analyzing");

  // 背景 Job：analyzing 時輪詢列表（離開頁面不影響後端 worker）
  useEffect(() => {
    if (!anyAnalyzing) return;
    setMessage((cur) => (cur ? cur : t("persona.jobRunning")));
    const id = window.setInterval(() => {
      void load();
    }, 2500);
    return () => window.clearInterval(id);
  }, [anyAnalyzing, repos.personas]); // eslint-disable-line react-hooks/exhaustive-deps

  // job 進度／終態 → 同步 message；完成後 reload 人設
  useEffect(() => {
    if (!analyzeJob) return;
    const active =
      analyzeJob.status === "pending" ||
      analyzeJob.status === "queued" ||
      analyzeJob.status === "running";
    if (active) {
      setMessage(
        `${jobTemplateLabel(analyzeJob.template_type, t)} · ${analyzeJob.progress_percent}% · ${
          analyzeJob.progress_summary || jobStatusLabel(analyzeJob.status, t)
        }`,
      );
      return;
    }
    if (analyzeJob.status === "succeeded") {
      setMessage(t("persona.jobDone"));
      setDetailTab("fingerprint");
      void load();
      refresh();
    } else if (analyzeJob.status === "failed") {
      setMessage(analyzeJob.error || analyzeJob.progress_summary || t("persona.jobFailed"));
      void load();
      refresh();
    }
  }, [analyzeJob?.id, analyzeJob?.status, analyzeJob?.progress_percent, analyzeJob?.progress_summary, jobRevision]); // eslint-disable-line react-hooks/exhaustive-deps

  // 輪詢到結果：ready → 指紋；失敗回 empty → 顯示 notes
  const selectedStatus = selected?.status;
  const selectedNotes = selected?.notes;
  useEffect(() => {
    if (!selected) return;
    if (selectedStatus === "ready" && message && /背景|background|Queued|排入|job|分析|%/i.test(message)) {
      setMessage(t("persona.jobDone"));
      setDetailTab("fingerprint");
      refresh();
    } else if (
      selectedStatus === "empty" &&
      selectedNotes &&
      /分析失敗|⚠️/.test(selectedNotes) &&
      message &&
      /背景|background|Queued|排入|job|分析中|%/i.test(message)
    ) {
      setMessage(selectedNotes);
      refresh();
    }
  }, [selectedStatus, selectedNotes]); // eslint-disable-line react-hooks/exhaustive-deps

  function selectPersona(id: string) {
    setSelectedId(id);
    setMessage("");
    setPreviewPost("");
    setPreviewReply("");
    setPromptPreview("");
    setShowPrompt(false);
    setMobileShowDetail(true);
    // 未 ready 預設帶到分析
    const p = personas.find((x) => x.id === id);
    if (p && !isPersonaReady(p)) setDetailTab("analyze");
    else setDetailTab("overview");
  }

  async function createPersona() {
    setBusy("create");
    try {
      const p = createEmptyPersona({
        id: newId("persona"),
        name: t("persona.newName"),
        brief: "",
        status: "empty",
      });
      await repos.personas.save(p);
      setSelectedId(p.id);
      setDetailTab("analyze");
      setMobileShowDetail(true);
      setMessage(t("persona.created"));
      refresh();
      await load();
    } finally {
      setBusy("");
    }
  }

  async function saveBasics() {
    if (!selected) return;
    setBusy("save");
    try {
      const draftText =
        selected.style.draftText.trim() || serializeDraftText(selected.style.draft);
      const next = markReady({
        ...selected,
        style: { ...selected.style, draftText },
        voice: selected.style.draft.tone || selected.voice,
      });
      if (!draftText) next.status = "empty";
      await repos.personas.save(next);
      setMessage(t("persona.saved"));
      refresh();
      await load();
    } finally {
      setBusy("");
    }
  }

  async function runAnalyzeFromText() {
    if (!selected) return;
    setBusy("analyze");
    setMessage("");
    try {
      const next = await repos.personas.analyzeFromText(
        selected.id,
        refText,
        sourceLabel || undefined,
      );
      setSelectedId(next.id);
      // live：立刻回 analyzing + 背景 job；mock／同步：可能已 ready
      if (next.status === "analyzing") {
        setMessage(t("persona.jobQueued"));
        setRefText("");
        void reloadJobs();
      } else {
        setMessage(t("persona.textDone", { n: next.style.sampleCount }));
        setRefText("");
        setDetailTab("fingerprint");
      }
      refresh();
      await load();
    } catch (e) {
      setMessage(e instanceof Error ? e.message : t("persona.analyzeFail"));
    } finally {
      setBusy("");
    }
  }

  async function runAnalyzeFromAccount() {
    if (!selected) return;
    setBusy("analyze");
    setMessage(t("persona.jobQueuedCrawl"));
    try {
      const next = await repos.personas.analyzeFromAccount(selected.id, benchmarkUsername);
      setSelectedId(next.id);
      if (next.status === "analyzing") {
        setMessage(t("persona.jobQueuedCrawl"));
        void reloadJobs();
      } else {
        setMessage(
          t("persona.accountDone", {
            user: next.style.benchmarkUsername || benchmarkUsername,
            n: next.style.sampleCount,
          }),
        );
        setDetailTab("fingerprint");
      }
      refresh();
      await load();
    } catch (e) {
      setMessage(e instanceof Error ? e.message : t("persona.analyzeFail"));
    } finally {
      setBusy("");
    }
  }

  async function setDefault() {
    if (!selected) return;
    await repos.personas.setActiveId(selected.id);
    setActiveId(selected.id);
    setMessage(t("persona.setDefaultMsg", { name: selected.name }));
    refresh();
  }

  async function removePersona() {
    if (!selected) return;
    if (!window.confirm(t("persona.confirmDelete", { name: selected.name }))) return;
    setBusy("delete");
    try {
      await repos.personas.remove(selected.id);
      setSelectedId("");
      setMobileShowDetail(false);
      setMessage(t("persona.deleted"));
      refresh();
      await load();
    } finally {
      setBusy("");
    }
  }

  function patchSelected(partial: Partial<Persona>) {
    if (!selected) return;
    setPersonas((list) => list.map((p) => (p.id === selected.id ? { ...p, ...partial } : p)));
  }

  function patchDraftText(text: string) {
    if (!selected) return;
    patchSelected({
      style: { ...selected.style, draftText: text },
      status: text.trim() ? "ready" : selected.status,
    });
  }

  async function runPreview() {
    if (!selected || !isPersonaReady(selected)) {
      setMessage(t("persona.needReady"));
      return;
    }
    setBusy("preview");
    setMessage(t("persona.previewRunning"));
    // 成功前保留舊結果，避免逾時後畫面一片空白
    try {
      const out = await repos.compose.personaPreview({
        personaId: selected.id,
        useNews: true,
      });
      setPreviewPost(out.post_text || "");
      setPreviewReply(out.reply_text || "");
      setPreviewTopic(out.topic || "");
      setPreviewTopicSource(out.topic_source || "");
      setPreviewNotes(out.notes || "");
      setPromptPreview(buildPersonaPromptBlock(selected, "post"));
      if (!out.post_text?.trim()) {
        setMessage(t("persona.previewFail"));
        return;
      }
      const srcLabel =
        out.topic_source === "news"
          ? t("persona.topicNews")
          : out.topic_source === "manual"
            ? t("persona.topicManual")
            : t("persona.topicFallback");
      setMessage(
        t("persona.previewDone", {
          topic: out.topic || "—",
          source: srcLabel,
        }),
      );
    } catch (e) {
      setMessage(e instanceof Error ? e.message : t("persona.previewFail"));
    } finally {
      setBusy("");
    }
  }

  const hasAnalysis =
    selected &&
    (selected.status === "ready" || Object.keys(selected.style.dimensions).length > 0);

  const listPane = (
    <div className="hb-md-list">
      <div className="hb-toolbar">
        <Button type="button" onClick={() => void createPersona()} disabled={busy === "create"}>
          {busy === "create" ? "…" : t("persona.add")}
        </Button>
      </div>
      {personas.length === 0 ? (
        <EmptyState title={t("persona.empty")} description={t("persona.emptyDesc")} />
      ) : (
        <ul className="hb-persona-list">
          {personas.map((p) => (
            <li key={p.id}>
              <button
                type="button"
                className={`hb-persona-item ${selected?.id === p.id ? "is-active" : ""}`}
                onClick={() => selectPersona(p.id)}
              >
                <span className="hb-persona-item__name">{p.name}</span>
                <span className="hb-inline-badges">
                  <Badge
                    tone={
                      p.status === "ready" ? "success" : p.status === "analyzing" ? "warning" : "neutral"
                    }
                  >
                    {statusLabel(p.status)}
                  </Badge>
                  {activeId === p.id ? <Badge tone="brand">{t("persona.default")}</Badge> : null}
                </span>
                <span className="text-muted hb-persona-item__tone">{toneOf(p) || t("common.dash")}</span>
                {p.learning_summary ? (
                  <span
                    className="text-muted"
                    style={{ display: "block", fontSize: "var(--hb-text-2xs)" }}
                  >
                    {p.learning_summary}
                  </span>
                ) : null}
              </button>
            </li>
          ))}
        </ul>
      )}
    </div>
  );

  const detailPane = selected ? (
    <div className="hb-md-detail">
      <div className="hb-md-detail__head">
        <button
          type="button"
          className="hb-back-link"
          onClick={() => setMobileShowDetail(false)}
        >
          {t("persona.backList")}
        </button>
        <div className="hb-md-detail__title">
          <strong>{selected.name}</strong>
          <Badge
            tone={
              selected.status === "ready"
                ? "success"
                : selected.status === "analyzing"
                  ? "warning"
                  : "neutral"
            }
          >
            {statusLabel(selected.status)}
          </Badge>
        </div>
      </div>

      {loadError ? (
        <p className="hb-banner-error" role="alert">
          {loadError}
        </p>
      ) : null}
      {message ? (
        <p className="hb-banner-ok" role="status">
          {message}
        </p>
      ) : null}

      {analyzeJob &&
      (analyzeJob.status === "pending" ||
        analyzeJob.status === "queued" ||
        analyzeJob.status === "running" ||
        analyzeJob.status === "succeeded" ||
        analyzeJob.status === "failed") ? (
        <div className="hb-persona-job" role="status" aria-live="polite">
          <div className="hb-persona-job__head">
            <strong>{jobTemplateLabel(analyzeJob.template_type, t)}</strong>
            <Badge
              tone={
                analyzeJob.status === "succeeded"
                  ? "success"
                  : analyzeJob.status === "failed"
                    ? "danger"
                    : "warning"
              }
            >
              {jobStatusLabel(analyzeJob.status, t)} · {analyzeJob.progress_percent}%
            </Badge>
          </div>
          {analyzeJob.progress_summary ? (
            <p className="text-muted hb-persona-job__sum">{analyzeJob.progress_summary}</p>
          ) : null}
          <div className="hb-progress" aria-hidden>
            <div
              className="hb-progress__bar"
              style={{ width: `${Math.min(100, Math.max(0, analyzeJob.progress_percent))}%` }}
            />
          </div>
          <Link to={`/app/jobs/${analyzeJob.id}`} className="hb-persona-job__link">
            {t("persona.openJob")}
          </Link>
        </div>
      ) : null}

      <div className="hb-tabs hb-tabs--sm" role="tablist">
        {(
          [
            ["overview", "persona.tabOverview"],
            ["analyze", "persona.tabAnalyze"],
            ["fingerprint", "persona.tabFingerprint"],
            ["preview", "persona.tabPreview"],
          ] as const
        ).map(([key, labelKey]) => (
          <button
            key={key}
            type="button"
            className={`hb-tab ${detailTab === key ? "is-active" : ""}`}
            onClick={() => setDetailTab(key)}
          >
            {t(labelKey)}
          </button>
        ))}
      </div>

      {detailTab === "overview" ? (
        <div className="hb-stack">
          <Input
            label={t("persona.name")}
            value={selected.name}
            onChange={(e) => patchSelected({ name: e.target.value })}
          />
          <Textarea
            label={t("persona.brief")}
            value={selected.brief}
            onChange={(e) => patchSelected({ brief: e.target.value })}
            placeholder={t("persona.briefPh")}
            rows={3}
          />
          <Input
            label={t("persona.avoid")}
            value={(selected.guard.avoid || []).join("、")}
            onChange={(e) =>
              patchSelected({
                guard: {
                  ...selected.guard,
                  avoid: e.target.value
                    .split(/[、,，]/)
                    .map((s) => s.trim())
                    .filter(Boolean),
                },
              })
            }
          />
          <p className="text-muted" style={{ fontSize: "var(--hb-text-xs)", margin: 0 }}>
            {t("persona.guardChars", { n: selected.guard.maxChars })}
            {selected.guard.banAiTone ? t("persona.banAi") : ""}
            {!isPersonaReady(selected) ? t("persona.notReadySuffix") : ""}
          </p>
          <div className="hb-wizard-actions">
            <Button type="button" onClick={() => void saveBasics()} disabled={busy === "save"}>
              {t("common.save")}
            </Button>
            <Button type="button" variant="ghost" onClick={() => void setDefault()}>
              {t("persona.setDefault")}
            </Button>
            <Button
              type="button"
              variant="danger"
              onClick={() => void removePersona()}
              disabled={busy === "delete"}
            >
              {t("common.delete")}
            </Button>
          </div>
        </div>
      ) : null}

      {detailTab === "analyze" ? (
        <div className="hb-stack">
          <div className="hb-tabs hb-tabs--sm" role="tablist">
            <button
              type="button"
              className={`hb-tab ${analyzeMode === "account" ? "is-active" : ""}`}
              onClick={() => setAnalyzeMode("account")}
            >
              {t("persona.modeAccount")}
            </button>
            <button
              type="button"
              className={`hb-tab ${analyzeMode === "text" ? "is-active" : ""}`}
              onClick={() => setAnalyzeMode("text")}
            >
              {t("persona.modeText")}
            </button>
          </div>

          {analyzeMode === "account" ? (
            <div className="hb-stack">
              <Input
                label={t("persona.username")}
                value={benchmarkUsername}
                onChange={(e) => setBenchmarkUsername(e.target.value.replace(/^@/, ""))}
                placeholder="harbor_main"
              />
              {accounts.length > 0 ? (
                <Select
                  label={t("persona.fromBound")}
                  value=""
                  onChange={(e) => {
                    if (e.target.value) setBenchmarkUsername(e.target.value);
                  }}
                >
                  <option value="">{t("persona.select")}</option>
                  {accounts.map((a) => (
                    <option key={a.id} value={a.username}>
                      {a.display_name} · @{a.username}
                    </option>
                  ))}
                </Select>
              ) : null}
              <Button
                type="button"
                onClick={() => void runAnalyzeFromAccount()}
                disabled={busy === "analyze" || !benchmarkUsername.trim()}
              >
                {busy === "analyze" ? t("persona.crawlBusy") : t("persona.crawlAnalyze")}
              </Button>
            </div>
          ) : (
            <div className="hb-stack">
              <Textarea
                label={t("persona.refText")}
                value={refText}
                onChange={(e) => setRefText(e.target.value)}
                placeholder={t("persona.refTextPh")}
                rows={6}
              />
              <Input
                label={t("persona.sourceLabel")}
                value={sourceLabel}
                onChange={(e) => setSourceLabel(e.target.value)}
                placeholder={t("persona.sourcePh")}
              />
              <Button
                type="button"
                onClick={() => void runAnalyzeFromText()}
                disabled={busy === "analyze" || !refText.trim()}
              >
                {busy === "analyze" ? t("persona.analyzeBusy") : t("persona.analyzeText")}
              </Button>
            </div>
          )}

          {hasAnalysis ? (
            <div className="hb-stack">
              <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)", margin: 0 }}>
                {t("persona.sampleMeta", { n: selected.style.sampleCount })}
                {" · "}
                {selected.style.source === "benchmark"
                  ? `@${selected.style.benchmarkUsername || t("common.dash")}`
                  : selected.style.source === "manual"
                    ? `${t("persona.sourceManual")}${selected.style.sourceLabel ? ` · ${selected.style.sourceLabel}` : ""}`
                    : selected.style.source}
              </p>
              <div className="hb-dim-grid">
                {DIM_ORDER.map((key) => {
                  const d = selected.style.dimensions[key as StyleDimKey];
                  if (!d?.summary) return null;
                  return (
                    <div key={key} className="hb-dim-card">
                      <strong>{t(`persona.dim.${key}`)}</strong>
                      <p>{d.summary}</p>
                    </div>
                  );
                })}
              </div>
              {selected.style.samplePreviews?.length ? (
                <ul className="hb-evidence" style={{ paddingLeft: "1.1rem" }}>
                  {selected.style.samplePreviews.slice(0, 3).map((s) => (
                    <li key={s.slice(0, 20)}>{s}</li>
                  ))}
                </ul>
              ) : null}
            </div>
          ) : (
            <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)" }}>
              {t("persona.analyzeHint")}
            </p>
          )}
        </div>
      ) : null}

      {detailTab === "fingerprint" ? (
        <div className="hb-stack">
          <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)", margin: 0 }}>
            {t("persona.fingerprintHint")}
          </p>
          <Textarea
            label={t("persona.fingerprint")}
            value={selected.style.draftText}
            onChange={(e) => patchDraftText(e.target.value)}
            placeholder={t("persona.fingerprintPh")}
            rows={14}
          />
          <Button type="button" onClick={() => void saveBasics()} disabled={busy === "save"}>
            {t("persona.saveFingerprint")}
          </Button>
        </div>
      ) : null}

      {detailTab === "preview" ? (
        <div className="hb-stack">
          <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)", margin: 0 }}>
            {t("persona.previewHint")}
          </p>
          <Button
            type="button"
            onClick={() => void runPreview()}
            disabled={!isPersonaReady(selected) || busy === "preview"}
          >
            {busy === "preview" ? t("persona.previewRunning") : t("persona.tryGen")}
          </Button>
          {!isPersonaReady(selected) ? (
            <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)" }}>
              {t("persona.notReadyMsg")}
            </p>
          ) : null}
          {previewTopic ? (
            <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)", margin: 0 }}>
              {t("persona.previewTopicLabel", {
                topic: previewTopic,
                source:
                  previewTopicSource === "news"
                    ? t("persona.topicNews")
                    : previewTopicSource === "manual"
                      ? t("persona.topicManual")
                      : t("persona.topicFallback"),
              })}
            </p>
          ) : null}
          {previewNotes ? (
            <p className="text-muted" style={{ fontSize: "var(--hb-text-xs)", margin: 0 }}>
              {previewNotes}
            </p>
          ) : null}
          {previewPost ? (
            <>
              <Textarea label={t("persona.rootPost")} value={previewPost} readOnly rows={6} />
              <Textarea label={t("persona.reply")} value={previewReply} readOnly rows={4} />
              <Button type="button" variant="ghost" onClick={() => setShowPrompt((v) => !v)}>
                {showPrompt ? t("persona.hidePrompt") : t("persona.showPrompt")}
              </Button>
              {showPrompt ? (
                <Textarea label={t("persona.promptBlock")} value={promptPreview} readOnly rows={8} />
              ) : null}
            </>
          ) : null}
        </div>
      ) : null}
    </div>
  ) : (
    <div className="hb-md-detail">
      <EmptyState title={t("persona.pickOne")} description={t("persona.pickDesc")} />
    </div>
  );

  return (
    <div
      className={`hb-master-detail ${mobileShowDetail ? "is-detail" : "is-list"}`}
    >
      {listPane}
      {detailPane}
    </div>
  );
}
