import { useEffect, useState } from "react";
import { useRepos } from "../../data/DataContext";
import type { Brand, BrandProduct, CostPreview, ExploreResult, WatchTermSuggestion } from "../../domain/types";
import { useI18n } from "../../i18n/I18nContext";
import { useFormatApiError } from "../../lib/apiErrors";
import { checkThreadsTerm, isThreadsSearchable, normalizeSearchTerm } from "../../lib/threadsTerm";
import { AppIcon, Badge, Button, Input } from "../ui";
import { CostPreviewDialog } from "./CostPreviewDialog";

const MAX_TERMS = 6;
const SUGGEST_LIMIT = 12;

/**
 * 商機頁「立即探索」：建議短詞 chips → 使用者審過後送 POST /radar/explore，
 * 走與每日巡同一套五問判定（契約 B）。
 */
export function ExplorePanel({ onExplored }: { onExplored: () => void }) {
  const { t } = useI18n();
  const repos = useRepos();
  const formatError = useFormatApiError();
  const [terms, setTerms] = useState<string[]>([]);
  const [draft, setDraft] = useState("");
  const [draftErr, setDraftErr] = useState("");
  const [suggestions, setSuggestions] = useState<WatchTermSuggestion[]>([]);
  const [loadingSuggest, setLoadingSuggest] = useState(true);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const [result, setResult] = useState<ExploreResult | null>(null);
  const [preview, setPreview] = useState<CostPreview | null>(null);
  const [brands, setBrands] = useState<Brand[]>([]);
  const [products, setProducts] = useState<BrandProduct[]>([]);
  const [brandId, setBrandId] = useState("");
  const [productId, setProductId] = useState("");
  const scout = (repos as unknown as { scout?: { listBrands: () => Promise<Brand[]>; listProducts: (id: string) => Promise<BrandProduct[]> } }).scout;

  useEffect(() => {
    let alive = true;
    setLoadingSuggest(true);
    repos.radar
      .suggestWatchTerms(scout ? { limit: SUGGEST_LIMIT, brand_id: brandId || undefined, product_id: productId || undefined } : SUGGEST_LIMIT)
      .then((list) => {
        if (!alive) return;
        const includes = list.filter((s) => s.usage === "include" && isThreadsSearchable(s.term));
        setSuggestions(includes);
        // pre-fill up to 4 searchable suggestions if user has none yet
        setTerms((prev) =>
          prev.length > 0 ? prev : includes.slice(0, 4).map((s) => normalizeSearchTerm(s.term)),
        );
      })
      .catch((e) => {
        if (alive) setErr(formatError(e));
      })
      .finally(() => {
        if (alive) setLoadingSuggest(false);
      });
    return () => {
      alive = false;
    };
    // 只在掛載時拉一次建議；repos 在 mock 裡每次 render 是新物件，不能當 dependency。
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [brandId, productId]);

  useEffect(() => { if (scout) void scout.listBrands().then(setBrands).catch(() => setBrands([])); }, [scout]);
  useEffect(() => { if (!scout || !brandId) { setProducts([]); return; } void scout.listProducts(brandId).then(setProducts).catch(() => setProducts([])); }, [scout, brandId]);

  function addTerm(raw: string) {
    const term = normalizeSearchTerm(raw);
    const check = checkThreadsTerm(term);
    if (!check.ok) {
      setDraftErr(t(`radar.explore.termError.${check.reason}`));
      return;
    }
    if (terms.some((x) => x.toLowerCase() === term.toLowerCase())) {
      setDraftErr(t("radar.explore.termError.duplicate"));
      return;
    }
    if (terms.length >= MAX_TERMS) {
      setDraftErr(t("radar.explore.termError.max"));
      return;
    }
    setTerms((prev) => [...prev, term]);
    setDraft("");
    setDraftErr("");
  }

  function removeTerm(term: string) {
    setTerms((prev) => prev.filter((x) => x !== term));
  }

  async function execute(confirmedPreview?: CostPreview, creditCeiling?: number) {
    setBusy(true);
    setErr("");
    setResult(null);
    try {
      const context = {
        brand_id: brandId || undefined,
        product_id: productId || undefined,
        preview_id: confirmedPreview?.preview_id,
        credit_ceiling: creditCeiling,
      };
      const res = scout
        ? await repos.radar.exploreOpportunities(terms, context)
        : confirmedPreview
          ? await repos.radar.exploreOpportunities(terms, context)
          : await repos.radar.exploreOpportunities(terms);
      setResult(res);
      setPreview(null);
      onExplored();
    } catch (e) {
      setErr(formatError(e));
    } finally {
      setBusy(false);
    }
  }

  async function submit() {
    if (terms.length === 0) {
      setErr(t("radar.explore.needTerms"));
      return;
    }
    if (scout && (!brandId || !productId)) {
      setErr(t("radar.explore.needProduct"));
      return;
    }
    const previewFn = (repos.radar as unknown as { getCostPreview?: (input: { action: string; product_id?: string; candidate_limit?: number }) => Promise<CostPreview> }).getCostPreview;
    // Older page-test repositories do not expose the optional preview seam yet;
    // preserving their direct path keeps the mock/live interface compatible.
    if (typeof previewFn !== "function") {
      await execute();
      return;
    }
    setBusy(true);
    setErr("");
    try {
      setPreview(await previewFn({ action: "explore", product_id: productId || undefined, candidate_limit: Math.max(terms.length * 4, 4) }));
    } catch (e) {
      setErr(formatError(e));
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="hb-radar-section hb-radar-explore">
      <h3 className="hb-radar-section__title">{t("radar.explore.title")}</h3>
      <p className="hb-radar-section__hint">{t("radar.explore.hint")}</p>
      {brands.length ? <div className="hb-radar-actions"><label>{t("radar.inbox.brand")}<select value={brandId} onChange={(e) => { setBrandId(e.target.value); setProductId(""); }}><option value="">{t("radar.explore.pickBrand")}</option>{brands.map((b) => <option key={b.id} value={b.id}>{b.display_name}</option>)}</select></label><label>{t("radar.inbox.product")}<select value={productId} disabled={!brandId} onChange={(e) => setProductId(e.target.value)}><option value="">{t("radar.explore.pickProduct")}</option>{products.map((p) => <option key={p.id} value={p.id}>{p.label}</option>)}</select></label></div> : null}

      {loadingSuggest ? (
        <p className="hb-radar-section__hint">{t("radar.explore.loadingSuggest")}</p>
      ) : null}

      {suggestions.length > 0 ? (
        <div className="hb-radar-explore__suggest">
          <p className="hb-field__label">{t("radar.explore.suggestions")}</p>
          <div className="hb-radar-actions">
            {suggestions.map((s) => {
              const already = terms.some((x) => x.toLowerCase() === s.term.toLowerCase());
              return (
                <Button
                  key={s.term}
                  type="button"
                  variant={already ? "ghost" : "secondary"}
                  disabled={already || terms.length >= MAX_TERMS || busy}
                  onClick={() => addTerm(s.term)}
                  title={s.reason}
                >
                  {s.term}
                </Button>
              );
            })}
          </div>
        </div>
      ) : null}

      <div className="hb-radar-explore__chips" aria-label={t("radar.explore.selected")}>
        {terms.length === 0 ? (
          <p className="hb-radar-section__hint">{t("radar.explore.emptyTerms")}</p>
        ) : (
          terms.map((term) => (
            <button
              key={term}
              type="button"
              className="hb-radar-explore__chip"
              onClick={() => removeTerm(term)}
              disabled={busy}
              title={t("radar.explore.removeChip")}
            >
              <Badge tone="brand">{term}</Badge>
              <span className="hb-radar-explore__chip-x" aria-hidden>
                <AppIcon name="close" size={14} reverse />
              </span>
            </button>
          ))
        )}
      </div>

      <div className="hb-radar-explore__add">
        <Input
          label={t("radar.explore.addLabel")}
          value={draft}
          onChange={(e) => {
            setDraft(e.target.value);
            setDraftErr("");
          }}
          onKeyDown={(e) => {
            if (e.key === "Enter") {
              e.preventDefault();
              addTerm(draft);
            }
          }}
          placeholder={t("radar.explore.addPh")}
          disabled={busy || terms.length >= MAX_TERMS}
        />
        <Button type="button" variant="secondary" disabled={busy} onClick={() => addTerm(draft)}>
          {t("radar.explore.add")}
        </Button>
      </div>
      {draftErr ? (
        <p className="hb-banner-error" role="alert">
          {draftErr}
        </p>
      ) : null}

      <div className="hb-radar-actions">
        <Button type="button" disabled={busy || terms.length === 0} onClick={() => void submit()}>
          {busy ? t("radar.explore.running") : t("radar.explore.run")}
        </Button>
      </div>

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

      {preview ? <CostPreviewDialog preview={preview} busy={busy} onCancel={() => setPreview(null)} onConfirm={(ceiling) => void execute(preview, ceiling)} /> : null}

      {result ? (
        <div className="hb-radar-explore__result" role="status">
          <p>
            {t("radar.explore.result", {
              hits: result.hit_count,
              created: result.created_count,
              judged: result.judged_count,
            })}
          </p>
          <p className="hb-radar-section__hint">{t("radar.explore.productStats", { created: result.created_count, merged: result.merged_count ?? 0, matched: result.matched_count ?? result.judged_count })}</p>
          {result.created_count === 0 ? (
            <p className="hb-radar-section__hint">{t("radar.explore.resultZeroHint")}</p>
          ) : null}
          {result.truncated_count > 0 ? (
            <p className="hb-radar-section__hint">
              {t("radar.explore.resultTruncated", { n: result.truncated_count })}
            </p>
          ) : null}
        </div>
      ) : null}
    </div>
  );
}
