import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { PostMetrics, postTypeLabel } from "../../components/studio/PostMetrics";
import { ReplyComposer, type ReplySelection } from "../../components/studio/ReplyComposer";
import { Badge, Button, Card, EmptyState, Textarea } from "../../components/ui";
import { useData, useRepos } from "../../data/DataContext";
import type { OwnPost, OwnPostReply, Persona, ThreadsAccount } from "../../domain/types";
import { useI18n } from "../../i18n/I18nContext";
import { useFormatApiError } from "../../lib/apiErrors";
import { buildStructureNotes, saveComposeMimicBridge } from "../../lib/composeBridge";
import { allowHttpUrl } from "../../lib/externalUrl";
import { isPersonaReady } from "../../lib/personaPrompt";
import { formatLocalDateTime } from "../../lib/time";

type Props = {
  /** 頂部預設帳號（貼文列表視角） */
  accountId: string;
  /** 頂部預設人設 */
  personaId: string;
  accounts: ThreadsAccount[];
  personas: Persona[];
};

type ReplyFilter = "pending" | "replied" | "all";

function defaultSelection(accountId: string, personaId: string): ReplySelection {
  return { accountId, personaId };
}

/**
 * 第一層來訊（別人留在貼文下，不是子留言）。
 * Threads API 的 replied_to 常等於「根貼 media_id」——那仍算第一層，不能當巢狀濾掉。
 */
function isTopLevelIncoming(
  r: OwnPostReply,
  myUsernames: Set<string>,
  rootMediaId?: string,
): boolean {
  const parent = (r.parent_reply_id || "").trim();
  if (parent && parent !== (rootMediaId || "").trim()) {
    // 真·巢狀回覆（parent 是另一則留言）
    return false;
  }
  if (r.is_mine) return false;
  if (r.username && myUsernames.has(r.username)) return false;
  return true;
}

function childrenOf(all: OwnPostReply[], parentId: string): OwnPostReply[] {
  return all
    .filter((r) => r.parent_reply_id === parentId)
    .slice()
    .sort((a, b) => a.created_at - b.created_at);
}

/** 底下是否有我的回覆（純留言樹判斷，不靠 LLM） */
function hasMyChildReply(
  all: OwnPostReply[],
  parentId: string,
  myUsernames: Set<string>,
): boolean {
  return all.some(
    (r) =>
      r.parent_reply_id === parentId &&
      (r.is_mine || (r.username ? myUsernames.has(r.username) : false)),
  );
}

/**
 * 未回覆：別人的第一層留言，且底下還沒有我的子回覆。
 * 已回覆：底下已有 is_mine／我的帳號 username 的回覆，或後端 reply_status=replied。
 */
function isReplyHidden(r: OwnPostReply): boolean {
  return (r.hide_status || "").toUpperCase() === "HIDDEN";
}

function isPendingReply(
  r: OwnPostReply,
  all: OwnPostReply[],
  myUsernames: Set<string>,
): boolean {
  if (hasMyChildReply(all, r.id, myUsernames)) return false;
  if (r.reply_status === "replied") return false;
  return true;
}

export function OwnPostsPanel({ accountId, personaId, accounts, personas }: Props) {
  const repos = useRepos();
  const { refresh, tick } = useData();
  const { t } = useI18n();
  const formatError = useFormatApiError();
  const navigate = useNavigate();
  const [posts, setPosts] = useState<OwnPost[]>([]);
  const [syncedAt, setSyncedAt] = useState<number | null>(null);
  const [expanded, setExpanded] = useState("");
  /** 每筆回覆草稿 key = postId 或 postId:replyId */
  const [draftByKey, setDraftByKey] = useState<Record<string, string>>({});
  /** 每筆回覆的帳號／人設（預設吃頂部） */
  const [selByKey, setSelByKey] = useState<Record<string, ReplySelection>>({});
  /** 哪些貼文已手動按過「分析結構」（才顯示 AI 分析結果） */
  const [analyzedIds, setAnalyzedIds] = useState<Record<string, boolean>>({});
  /** 哪些 key 已打開回覆編輯區 */
  const [composeOpen, setComposeOpen] = useState<Record<string, boolean>>({});
  /** 留言篩選：預設未回覆 */
  const [replyFilter, setReplyFilter] = useState<ReplyFilter>("pending");
  const [busy, setBusy] = useState("");
  const [message, setMessage] = useState("");
  const [messageTone, setMessageTone] = useState<"ok" | "error">("ok");
  const [verifyUrl, setVerifyUrl] = useState("");
  /** 本頁已載過留言的 post id（避免每次展開重打） */
  const [repliesLoaded, setRepliesLoaded] = useState<Record<string, boolean>>({});


  const myUsernames = new Set(accounts.map((a) => a.username));

  useEffect(() => {
    void (async () => {
      if (!accountId) {
        setPosts([]);
        return;
      }
      setPosts(await repos.ownPosts.list(accountId));
      setSyncedAt(await repos.ownPosts.lastSyncedAt());
    })();
  }, [accountId, repos.ownPosts, tick]);

  function flashOk(text: string, url = "") {
    setMessageTone("ok");
    setMessage(text);
    setVerifyUrl(url);
  }

  function flashErr(err: unknown, fallback: string) {
    setMessageTone("error");
    setMessage(formatError(err, fallback));
    setVerifyUrl("");
  }

  function getSel(key: string): ReplySelection {
    return selByKey[key] || defaultSelection(accountId, personaId);
  }

  function setSel(key: string, next: ReplySelection) {
    setSelByKey((m) => ({ ...m, [key]: next }));
  }

  function openCompose(key: string) {
    setComposeOpen((m) => ({ ...m, [key]: true }));
    setSelByKey((m) => ({
      ...m,
      [key]: m[key] || defaultSelection(accountId, personaId),
    }));
    if (!draftByKey[key]) {
      setDraftByKey((m) => ({ ...m, [key]: m[key] || "" }));
    }
  }

  async function sync() {
    if (!accountId) return;
    setBusy("sync");
    setMessage("");
    setMessageTone("ok");
    setVerifyUrl("");
    try {
      const list = await repos.ownPosts.sync(accountId);
      setPosts(list);
      setSyncedAt(await repos.ownPosts.lastSyncedAt());
      // 重新同步後留言改點開再載
      setRepliesLoaded({});
      flashOk(t("posts.syncDone", { n: list.length }));
      refresh();
    } catch (e) {
      flashErr(e, "posts.syncFail");
    } finally {
      setBusy("");
    }
  }

  async function toggleReplies(post: OwnPost) {
    if (expanded === post.id) {
      setExpanded("");
      return;
    }
    setExpanded(post.id);
    // 已載過或本機已有留言：不再打 API
    if (repliesLoaded[post.id] || (post.replies?.length ?? 0) > 0) {
      return;
    }
    setBusy(`replies:${post.id}`);
    setMessage("");
    try {
      const next = await repos.ownPosts.loadReplies(post.id);
      setPosts((list) => list.map((p) => (p.id === next.id ? next : p)));
      setRepliesLoaded((m) => ({ ...m, [post.id]: true }));
    } catch (e) {
      flashErr(e, "posts.loadRepliesFail");
    } finally {
      setBusy("");
    }
  }

  async function genReply(key: string, post: OwnPost, replyId?: string) {
    const sel = getSel(key);
    const persona = personas.find((p) => p.id === sel.personaId);
    if (!isPersonaReady(persona)) {
      flashErr(new Error(t("posts.needPersona")), "posts.needPersona");
      return;
    }
    setBusy(key);
    setMessage("");
    try {
      const text = await repos.ownPosts.generateReply({
        postId: post.id,
        replyId,
        personaId: sel.personaId,
      });
      setDraftByKey((m) => ({ ...m, [key]: text }));
      setComposeOpen((m) => ({ ...m, [key]: true }));
    } catch (e) {
      flashErr(e, "posts.genFail");
    } finally {
      setBusy("");
    }
  }

  async function send(key: string, post: OwnPost, replyId?: string) {
    const text = draftByKey[key];
    const sel = getSel(key);
    if (!text?.trim()) {
      flashErr(new Error(t("posts.needText")), "posts.needText");
      return;
    }
    if (!sel.accountId) {
      flashErr(new Error(t("posts.needAccount")), "posts.needAccount");
      return;
    }
    setBusy(`send:${key}`);
    flashOk(t("posts.sending"));
    try {
      // 回覆留言只送文字，不附圖
      const next = await repos.ownPosts.sendReply({
        postId: post.id,
        replyId,
        text,
        accountId: sel.accountId,
      });
      setPosts((list) => list.map((p) => (p.id === next.id ? next : p)));
      setRepliesLoaded((m) => ({ ...m, [post.id]: true }));
      const user =
        accounts.find((a) => a.id === sel.accountId)?.username || t("posts.accountFallback");
      flashOk(t("posts.sent", { user }), allowHttpUrl(next.permalink || post.permalink) || "");
      setComposeOpen((m) => ({ ...m, [key]: false }));
      setDraftByKey((m) => ({ ...m, [key]: "" }));
      setExpanded(post.id);
      refresh();
    } catch (e) {
      flashErr(e, "posts.sendFail");
    } finally {
      setBusy("");
    }
  }

  async function manageReply(post: OwnPost, reply: OwnPostReply, hide: boolean) {
    setBusy(`hide:${reply.id}`);
    setMessage("");
    setVerifyUrl("");
    try {
      const next = await repos.ownPosts.manageReply({
        postId: post.id,
        replyId: reply.id,
        hide,
      });
      setPosts((list) => list.map((p) => (p.id === next.id ? next : p)));
      flashOk(
        hide ? t("posts.replyHidden") : t("posts.replyUnhidden"),
        allowHttpUrl(next.permalink || post.permalink) || "",
      );
    } catch (e) {
      flashErr(e, "posts.hideFail");
    } finally {
      setBusy("");
    }
  }

  async function analyze(post: OwnPost) {
    setBusy(`an:${post.id}`);
    setMessage("");
    setMessageTone("ok");
    try {
      const next = await repos.ownPosts.analyzePost(post.id);
      setPosts((list) => list.map((p) => (p.id === next.id ? next : p)));
      setAnalyzedIds((m) => ({ ...m, [post.id]: true }));
      setExpanded(post.id);
      flashOk(t("posts.analyzeDone"));
    } catch (e) {
      flashErr(e, "posts.analyzeFail");
    } finally {
      setBusy("");
    }
  }

  function openComposeMimic(post: OwnPost) {
    // 長文 + 結構分析走 sessionStorage，避免 query 截斷／帶不過分析
    const notes = buildStructureNotes({
      insight: post.insight,
      formulaSummary: post.formula_summary,
      formulaDetail: post.formula_detail,
    });
    saveComposeMimicBridge({
      sourceText: post.text || "",
      structureNotes: notes || undefined,
      formulaSummary: post.formula_summary,
      insight: post.insight,
      fromPostId: post.id,
    });
    navigate(`/app/studio?tab=compose&from=own-post&mimic=1`);
  }

  return (
    <div className="hb-stack">
      <div className="hb-toolbar">
        <Button type="button" variant="ghost" onClick={() => void sync()} disabled={busy === "sync" || !accountId}>
          {busy === "sync" ? t("posts.syncing") : t("posts.sync")}
        </Button>
        <p className="text-muted hb-toolbar__hint">
          {syncedAt ? t("posts.syncedAt", { time: formatLocalDateTime(syncedAt) }) : t("posts.notSynced")}
        </p>
      </div>
      {message ? (
        <p className={messageTone === "error" ? "hb-banner-error" : "hb-banner-ok"} role={messageTone === "error" ? "alert" : "status"}>
          {message}
          {verifyUrl ? (
            <>
              {" "}
              <a href={verifyUrl} target="_blank" rel="noreferrer">
                {t("posts.openThreads")}
              </a>
            </>
          ) : null}
        </p>
      ) : null}

      {posts.length === 0 ? (
        <EmptyState title={t("posts.empty")} />
      ) : (
        posts.map((post) => {
          const open = expanded === post.id;
          const rootKey = post.id;
          // 本 session 按過分析，或後端已存結果（重整後仍顯示）
          const showAnalysis = Boolean(
            analyzedIds[post.id] ||
              post.formula_detail ||
              post.formula_summary ||
              post.insight,
          );
          return (
            <Card key={post.id}>
              <div className="hb-post-head">
                {post.thumbnail_url || post.media_url ? (
                  <img
                    className="hb-post-thumb"
                    src={post.thumbnail_url || post.media_url || ""}
                    alt=""
                    loading="lazy"
                  />
                ) : null}
                <div className="hb-post-head__body">
                  <div className="hb-inline-badges" style={{ marginBottom: "0.4rem" }}>
                    {post.topic_tag ? <Badge tone="brand">{post.topic_tag}</Badge> : null}
                    <Badge tone="neutral">{postTypeLabel(post, t)}</Badge>
                    {post.is_quote_post ? <Badge tone="brand">quote</Badge> : null}
                    {post.insights_status && post.insights_status !== "ok" ? (
                      <Badge tone="warning">{post.insights_status}</Badge>
                    ) : null}
                    {showAnalysis ? <Badge tone="success">{t("posts.analyzedBadge")}</Badge> : null}
                    {post.reply_control ? (
                      <Badge tone="neutral">
                        {t("posts.whoCanReply")}: {t(`posts.replyControl.${post.reply_control}`)}
                      </Badge>
                    ) : null}
                  </div>
                  <p style={{ margin: "0 0 0.5rem" }}>{post.text || t("posts.noText")}</p>
                  <PostMetrics post={post} variant="compact" />
                  <p className="text-muted hb-compact-row__meta">
                    {formatLocalDateTime(post.published_at)}
                    {post.shortcode ? ` · ${post.shortcode}` : ""}
                    {allowHttpUrl(post.permalink) ? (
                      <>
                        {" · "}
                        <a href={allowHttpUrl(post.permalink) ?? undefined} target="_blank" rel="noreferrer">
                          {t("posts.openThreads")}
                        </a>
                      </>
                    ) : null}
                  </p>
                </div>
              </div>
              {open ? <PostMetrics post={post} variant="detail" /> : null}

              {/* AI 結構分析：有結果就顯示；詳細區在展開時更清楚 */}
              {showAnalysis && post.insight ? (
                <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)" }}>
                  {t("posts.insight", { text: post.insight })}
                </p>
              ) : null}
              {showAnalysis && post.formula_summary ? (
                <p className="text-muted" style={{ fontSize: "var(--hb-text-xs)" }}>
                  {t("posts.review", { text: post.formula_summary })}
                </p>
              ) : null}
              {showAnalysis && post.formula_detail ? (
                <Textarea label={t("posts.formulaResult")} value={post.formula_detail} readOnly rows={8} />
              ) : null}

              <div className="hb-wizard-actions">
                <Button
                  type="button"
                  variant="ghost"
                  disabled={busy === `replies:${post.id}`}
                  onClick={() => void toggleReplies(post)}
                >
                  {(() => {
                    if (busy === `replies:${post.id}`) return t("posts.loadingReplies");
                    const incoming = post.replies.filter((r) =>
                      isTopLevelIncoming(r, myUsernames, post.media_id),
                    );
                    const pendingN = incoming.filter((r) =>
                      isPendingReply(r, post.replies, myUsernames),
                    ).length;
                    const total = Math.max(incoming.length, post.reply_count || 0);
                    return open
                      ? t("posts.collapseReplies")
                      : t("posts.repliesBtn", { total, pending: pendingN });
                  })()}
                </Button>
                <Button
                  type="button"
                  variant="ghost"
                  onClick={() => openCompose(rootKey)}
                >
                  {t("posts.replyRoot")}
                </Button>
                <Button
                  type="button"
                  variant="ghost"
                  disabled={busy === `an:${post.id}`}
                  onClick={() => void analyze(post)}
                >
                  {busy === `an:${post.id}`
                    ? t("posts.analyzing")
                    : showAnalysis
                      ? t("posts.reanalyze")
                      : t("posts.analyze")}
                </Button>
                <Button type="button" variant="ghost" onClick={() => openComposeMimic(post)}>
                  {t("posts.mimicThis")}
                </Button>
              </div>
              {composeOpen[rootKey] ? (
                <div style={{ marginTop: "0.65rem" }}>
                  <ReplyComposer
                    accounts={accounts}
                    personas={personas}
                    selection={getSel(rootKey)}
                    onSelectionChange={(s) => setSel(rootKey, s)}
                    text={draftByKey[rootKey] || ""}
                    onTextChange={(txt) => setDraftByKey((m) => ({ ...m, [rootKey]: txt }))}
                    onGenerate={() => void genReply(rootKey, post)}
                    onSend={() => void send(rootKey, post)}
                    generating={busy === rootKey}
                    sending={busy === `send:${rootKey}`}
                    label={t("posts.rootDraft")}
                  />
                </div>
              ) : null}

              {open ? (
                <div className="hb-stack" style={{ marginTop: "0.75rem" }}>
                  {busy === `replies:${post.id}` ? (
                    <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)" }}>
                      {t("posts.loadingReplies")}
                    </p>
                  ) : null}
                  {(() => {
                    const tops = post.replies.filter((r) =>
                      isTopLevelIncoming(r, myUsernames, post.media_id),
                    );
                    const pendingN = tops.filter((r) =>
                      isPendingReply(r, post.replies, myUsernames),
                    ).length;
                    const repliedN = tops.filter(
                      (r) => !isPendingReply(r, post.replies, myUsernames),
                    ).length;
                    const filtered = tops.filter((r) => {
                      const pend = isPendingReply(r, post.replies, myUsernames);
                      if (replyFilter === "pending") return pend;
                      if (replyFilter === "replied") return !pend;
                      return true;
                    });
                    return (
                      <>
                        <div className="hb-tabs hb-tabs--sm" role="tablist">
                          <button
                            type="button"
                            className={`hb-tab ${replyFilter === "pending" ? "is-active" : ""}`}
                            onClick={() => setReplyFilter("pending")}
                          >
                            {t("posts.filter.pending", { n: pendingN })}
                          </button>
                          <button
                            type="button"
                            className={`hb-tab ${replyFilter === "replied" ? "is-active" : ""}`}
                            onClick={() => setReplyFilter("replied")}
                          >
                            {t("posts.filter.replied", { n: repliedN })}
                          </button>
                          <button
                            type="button"
                            className={`hb-tab ${replyFilter === "all" ? "is-active" : ""}`}
                            onClick={() => setReplyFilter("all")}
                          >
                            {t("posts.filter.all", { n: tops.length })}
                          </button>
                        </div>
                        {filtered.length === 0 ? (
                          <p className="text-muted">
                            {replyFilter === "pending"
                              ? t("posts.noPending")
                              : replyFilter === "replied"
                                ? t("posts.noReplied")
                                : t("posts.noReplies")}
                          </p>
                        ) : (
                          filtered.map((r) => {
                            const key = `${post.id}:${r.id}`;
                            const pending = isPendingReply(r, post.replies, myUsernames);
                            const kids = childrenOf(post.replies, r.id);
                            return (
                              <div key={r.id} className={`hb-script-row${isReplyHidden(r) ? " is-hidden" : ""}`}>
                                <div className="hb-inline-badges" style={{ marginBottom: "0.35rem" }}>
                                  <Badge tone={pending ? "warning" : "success"}>
                                    {pending ? t("posts.status.pending") : t("posts.status.replied")}
                                  </Badge>
                                  {isReplyHidden(r) ? <Badge tone="neutral">{t("posts.hiddenBadge")}</Badge> : null}
                                  <strong>@{r.username}</strong>
                                  {typeof r.like_count === "number" ? (
                                    <span className="text-muted" style={{ fontSize: "var(--hb-text-xs)" }}>
                                      {t("posts.likesN", { n: r.like_count })}
                                    </span>
                                  ) : null}
                                  {kids.length > 0 ? (
                                    <span className="text-muted" style={{ fontSize: "var(--hb-text-xs)" }}>
                                      {t("posts.childCount", { n: kids.length })}
                                    </span>
                                  ) : null}
                                </div>
                                <p style={{ margin: "0.35rem 0" }}>{r.text}</p>

                                {/* 子留言：永遠顯示，不會因篩選或 is_mine 消失 */}
                                {kids.length > 0 ? (
                                  <div className="hb-reply-thread">
                                    {kids.map((c) => {
                                      const mine = c.is_mine || myUsernames.has(c.username);
                                      return (
                                        <div
                                          key={c.id}
                                          className={`hb-reply-child${mine ? " is-mine" : ""}`}
                                        >
                                          <div className="hb-inline-badges">
                                            {mine ? <Badge tone="brand">{t("posts.mine")}</Badge> : null}
                                            <strong>@{c.username}</strong>
                                            <span className="text-muted" style={{ fontSize: "var(--hb-text-2xs)" }}>
                                              {formatLocalDateTime(c.created_at)}
                                            </span>
                                          </div>
                                          <p style={{ margin: "0.25rem 0 0" }}>{c.text}</p>
                                        </div>
                                      );
                                    })}
                                  </div>
                                ) : null}

                                {/* 未回／已回都可再回：串成子留言 */}
                                <div className="hb-wizard-actions" style={{ marginTop: "0.35rem" }}>
                                  {!composeOpen[key] ? (
                                    <Button type="button" variant="ghost" onClick={() => openCompose(key)}>
                                      {pending ? t("posts.replyThis") : t("posts.replyAgain")}
                                    </Button>
                                  ) : null}
                                  <Button
                                    type="button"
                                    variant="ghost"
                                    disabled={busy === `hide:${r.id}`}
                                    onClick={() => void manageReply(post, r, !isReplyHidden(r))}
                                  >
                                    {busy === `hide:${r.id}`
                                      ? t("posts.hidingReply")
                                      : isReplyHidden(r)
                                        ? t("posts.unhideReply")
                                        : t("posts.hideReply")}
                                  </Button>
                                </div>
                                {composeOpen[key] ? (
                                  <ReplyComposer
                                    accounts={accounts}
                                    personas={personas}
                                    selection={getSel(key)}
                                    onSelectionChange={(s) => setSel(key, s)}
                                    text={draftByKey[key] || ""}
                                    onTextChange={(txt) => setDraftByKey((m) => ({ ...m, [key]: txt }))}
                                    onGenerate={() => void genReply(key, post, r.id)}
                                    onSend={() => void send(key, post, r.id)}
                                    generating={busy === key}
                                    sending={busy === `send:${key}`}
                                    label={
                                      pending
                                        ? t("posts.replyTo", { user: r.username })
                                        : t("posts.replyAgainTo", { user: r.username })
                                    }
                                  />
                                ) : null}
                              </div>
                            );
                          })
                        )}
                      </>
                    );
                  })()}
                </div>
              ) : null}
            </Card>
          );
        })
      )}
    </div>
  );
}
