import { useCallback, useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import { PageHeader } from "../components/layout/PageHeader";
import { Badge, Button, Card, EmptyState } from "../components/ui";
import { useData, useRepos } from "../data/DataContext";
import type { OutboxBundle, ThreadsAccount } from "../domain/types";
import { useI18n } from "../i18n/I18nContext";

function isInFlightBundle(b: OutboxBundle | null): boolean {
  if (!b) return false;
  if (b.status === "completed" || b.status === "cancelled") return false;
  return b.steps.some((s) => s.status === "scheduled" || s.status === "publishing");
}

export function OutboxDetailPage() {
  const { id } = useParams();
  const navigate = useNavigate();
  const repos = useRepos();
  const { refresh, tick } = useData();
  const { t } = useI18n();
  const [bundle, setBundle] = useState<OutboxBundle | null>(null);
  const [accounts, setAccounts] = useState<ThreadsAccount[]>([]);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(true);

  const [loadFailed, setLoadFailed] = useState(false);

  const load = useCallback(async () => {
    if (!id) return;
    try {
      const [b, acc] = await Promise.all([repos.outbox.get(id), repos.accounts.list()]);
      setBundle(b);
      setAccounts(acc);
      setLoadFailed(false);
      setError("");
    } catch (e) {
      // 載入失敗與「這篇不存在」是兩件事，分開記，否則畫面會謊稱找不到。
      setLoadFailed(true);
      setError(e instanceof Error ? e.message : t("outbox.detail.loadFail"));
    } finally {
      setLoading(false);
    }
  }, [id, repos.outbox, repos.accounts, t]);

  useEffect(() => {
    void load();
  }, [load, tick]);

  // 發文中自動輪詢：worker 可能 10～30s 才完成，不輪詢會一直卡舊狀態／舊錯誤。
  // 只看 inFlight 布林：依賴整個 bundle 的話，每次輪詢寫回新物件都會重建 interval。
  const inFlight = isInFlightBundle(bundle);
  useEffect(() => {
    if (!inFlight) return;
    const timer = window.setInterval(() => {
      void load();
    }, 2000);
    return () => window.clearInterval(timer);
  }, [inFlight, load]);

  async function run(action: () => Promise<OutboxBundle>) {
    setBusy(true);
    setError("");
    try {
      await action();
      refresh();
      await load();
    } catch (e) {
      setError(e instanceof Error ? e.message : t("outbox.detail.opFail"));
    } finally {
      setBusy(false);
    }
  }

  async function removeBundle() {
    if (!bundle) return;
    if (!window.confirm(t("outbox.confirmDelete", { title: bundle.title }))) return;
    setBusy(true);
    setError("");
    try {
      await repos.outbox.remove(bundle.id);
      refresh();
      navigate("/app/outbox");
    } catch (e) {
      setError(e instanceof Error ? e.message : t("outbox.deleteFail"));
      setBusy(false);
    }
  }

  if (!id) return <EmptyState title={t("outbox.detail.missingId")} />;
  if (loading && !bundle) return <EmptyState title={t("outbox.detail.loading")} />;
  if (!bundle && loadFailed) {
    return (
      <>
        <p className="hb-banner-error" role="alert">
          {error || t("outbox.detail.loadFail")}
        </p>
        <div className="hb-wizard-actions">
          <Button type="button" onClick={() => void load()}>
            {t("common.retry")}
          </Button>
          <Link to="/app/outbox" className="hb-btn hb-btn--ghost">
            {t("common.back")}
          </Link>
        </div>
      </>
    );
  }
  if (!bundle) return <EmptyState title={t("outbox.detail.notFound")} />;

  const nameOf = (accountId: string) =>
    accounts.find((a) => a.id === accountId)?.display_name || accountId;

  const allPublished = bundle.steps.length > 0 && bundle.steps.every((s) => s.status === "published");

  return (
    <>
      <PageHeader
        title={bundle.title}
        description={
          allPublished
            ? t("outbox.detail.doneHint")
            : inFlight
              ? t("outbox.detail.sendingHint")
              : bundle.status
        }
      />
      <div className="hb-wizard-actions">
        <Button type="button" variant="danger" disabled={busy} onClick={() => void removeBundle()}>
          {busy ? t("outbox.detail.processing") : t("outbox.detail.delete")}
        </Button>
        <Link to="/app/outbox" className="hb-btn hb-btn--ghost">
          {t("outbox.detail.back")}
        </Link>
      </div>
      {allPublished ? (
        <p className="hb-banner-ok" role="status">
          {t("outbox.detail.doneHint")}
        </p>
      ) : null}
      {inFlight ? (
        <p className="text-muted" style={{ fontSize: "var(--hb-text-sm)" }} role="status">
          {t("outbox.detail.sendingHint")}
        </p>
      ) : null}
      {error ? (
        <p className="hb-form-error" role="alert">
          {error}
        </p>
      ) : null}
      <div className="hb-stack">
        {bundle.steps.map((step, index) => {
          const showError = (step.status === "failed" || step.status === "blocked") && !!step.error;
          return (
            <Card key={step.id}>
              <div className="hb-list-row">
                <div>
                  <strong>
                    {step.kind === "root" ? t("outbox.detail.root") : t("outbox.detail.replyN", { n: index })} ·{" "}
                    {nameOf(step.account_id)}
                  </strong>
                  <p>{step.text}</p>
                  {/* 只有失敗才顯示 error；成功後不應再掛舊訊息 */}
                  {showError ? <p className="hb-form-error">{step.error}</p> : null}
                </div>
                <div className="hb-list-row__actions">
                  <Badge
                    tone={
                      step.status === "published"
                        ? "success"
                        : step.status === "failed" || step.status === "blocked"
                          ? "danger"
                          : step.status === "publishing"
                            ? "warning"
                            : "neutral"
                    }
                  >
                    {stepStatusLabel(t, step.status)}
                  </Badge>
                  {(step.status === "failed" || step.status === "blocked") && (
                    <Button
                      type="button"
                      variant="ghost"
                      disabled={busy}
                      onClick={() => void run(() => repos.outbox.retryStep(bundle.id, step.id))}
                    >
                      {t("outbox.detail.retry")}
                    </Button>
                  )}
                </div>
              </div>
            </Card>
          );
        })}
      </div>
    </>
  );
}

function stepStatusLabel(t: (k: string, p?: Record<string, string | number>) => string, status: string): string {
  switch (status) {
    case "published":
      return t("outbox.step.published");
    case "failed":
      return t("outbox.step.failed");
    case "publishing":
      return t("outbox.step.publishing");
    case "scheduled":
      return t("outbox.step.scheduled");
    case "blocked":
      return t("outbox.step.blocked");
    default:
      return status;
  }
}
