"use client";

import { ChangeEvent, ReactNode, useEffect, useMemo, useState } from "react";
import {
  Dimension,
  HandSide,
  Quota,
  Reading,
  ReadingSummary,
  ReadingType,
  ReportData,
  apiFetch,
  ensureToken,
  uploadFaceImage,
  uploadPalmImage,
} from "@/lib/api";

const handText: Record<HandSide, string> = {
  left: "左手",
  right: "右手",
  unknown: "不确定",
};

const statusText: Record<Reading["status"], string> = {
  pending: "等待中",
  processing: "生成中",
  completed: "已完成",
  failed: "失败",
};

const readingMeta: Record<ReadingType, { name: string; title: string; label: string; description: string }> = {
  palm: {
    name: "手相",
    title: "掌心解读",
    label: "PALM READING",
    description: "上传掌心照片，生成生活、学习、事业与关系提醒。",
  },
  face: {
    name: "面相",
    title: "气色与五官",
    label: "FACE READING",
    description: "上传单人正脸照，观察脸型、五官、气色与表达状态。",
  },
  bazi: {
    name: "八字",
    title: "生辰格局",
    label: "BAZI READING",
    description: "填写出生信息，排出四柱后生成生活化八字报告。",
  },
};

type View = "home" | ReadingType | "archive";
const views: View[] = ["home", "palm", "face", "bazi", "archive"];

type BaziForm = {
  nickname: string;
  gender: string;
  calendar_type: "solar" | "lunar";
  is_leap_month: boolean;
  birth_date: string;
  birth_time: string;
  time_unknown: boolean;
  birth_place: string;
};

type BaziChart = {
  solar_date?: string;
  lunar_date?: string;
  birth_time?: string | null;
  time_unknown?: boolean;
  birth_place?: string | null;
  pillars?: Record<string, string>;
  day_master?: string;
  wuxing_balance?: Record<string, number>;
};

const defaultBaziForm: BaziForm = {
  nickname: "",
  gender: "",
  calendar_type: "solar",
  is_leap_month: false,
  birth_date: "",
  birth_time: "12:00",
  time_unknown: false,
  birth_place: "",
};

export default function PalmWebApp({ initialView = "home" }: { initialView?: View }) {
  const [ready, setReady] = useState(false);
  const [palmFile, setPalmFile] = useState<File | null>(null);
  const [faceFile, setFaceFile] = useState<File | null>(null);
  const [palmPreview, setPalmPreview] = useState("");
  const [facePreview, setFacePreview] = useState("");
  const [handSide, setHandSide] = useState<HandSide>("unknown");
  const [baziForm, setBaziForm] = useState<BaziForm>(defaultBaziForm);
  const [busyText, setBusyText] = useState("");
  const [error, setError] = useState("");
  const [readings, setReadings] = useState<ReadingSummary[]>([]);
  const [quota, setQuota] = useState<Quota | null>(null);
  const [activeReading, setActiveReading] = useState<Reading | null>(null);
  const [activeView, setActiveView] = useState<View>(initialView);
  const [activeJobId, setActiveJobId] = useState("");
  const [activeJobType, setActiveJobType] = useState<ReadingType>("palm");

  useEffect(() => {
    setActiveView(readViewFromPath(initialView));
    const onPopState = () => setActiveView(readViewFromPath(initialView));
    window.addEventListener("popstate", onPopState);

    ensureToken()
      .then(() => Promise.all([loadReadings(), loadQuota()]))
      .then(() => setReady(true))
      .catch((err) => {
        setError(err.message || "初始化失败");
        setReady(true);
      });

    return () => window.removeEventListener("popstate", onPopState);
  }, [initialView]);

  useEffect(() => {
    return () => {
      if (palmPreview) URL.revokeObjectURL(palmPreview);
      if (facePreview) URL.revokeObjectURL(facePreview);
    };
  }, [palmPreview, facePreview]);

  const completedReadings = readings.filter((item) => item.status === "completed").length;
  const hasActiveJob = Boolean(activeJobId);

  function pickFile(event: ChangeEvent<HTMLInputElement>, type: "palm" | "face") {
    const selected = event.target.files?.[0];
    if (!selected) return;
    setError("");
    const url = URL.createObjectURL(selected);
    if (type === "palm") {
      if (palmPreview) URL.revokeObjectURL(palmPreview);
      setPalmFile(selected);
      setPalmPreview(url);
    } else {
      if (facePreview) URL.revokeObjectURL(facePreview);
      setFaceFile(selected);
      setFacePreview(url);
    }
  }

  async function loadReadings() {
    const data = await apiFetch<ReadingSummary[]>("/readings");
    setReadings(data);
  }

  async function loadQuota() {
    const data = await apiFetch<Quota>("/readings/quota");
    setQuota(data);
  }

  async function startImageReading(type: "palm" | "face") {
    if (quota && quota.remaining <= 0) {
      setError("今日 5 次解读机会已用完，请明天 0 点后再来。");
      return;
    }
    const file = type === "palm" ? palmFile : faceFile;
    if (!file) {
      setError(type === "palm" ? "请先选择一张清晰的掌心照片。" : "请先选择一张清晰的单人正脸照片。");
      return;
    }
    setBusyText(type === "palm" ? "正在接入掌纹照片..." : "正在接入正脸照片...");
    setError("");
    try {
      const upload = type === "palm" ? await uploadPalmImage(file) : await uploadFaceImage(file);
      const reading = await apiFetch<Reading>("/readings", {
        method: "POST",
        body: JSON.stringify({
          reading_type: type,
          image_id: upload.image_id,
          input_data: type === "palm" ? { hand_side: handSide } : { photo_style: "front_single" },
        }),
      });
      afterTaskCreated(reading);
      if (type === "palm") {
        setPalmFile(null);
        setPalmPreview("");
      } else {
        setFaceFile(null);
        setFacePreview("");
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "提交失败");
      setBusyText("");
    }
  }

  async function startBaziReading() {
    if (quota && quota.remaining <= 0) {
      setError("今日 5 次解读机会已用完，请明天 0 点后再来。");
      return;
    }
    if (!baziForm.birth_date) {
      setError("请先填写出生日期。");
      return;
    }
    if (!baziForm.time_unknown && !baziForm.birth_time) {
      setError("请选择出生时间，或勾选“不确定时辰”。");
      return;
    }
    setBusyText("正在排出四柱...");
    setError("");
    try {
      const reading = await apiFetch<Reading>("/readings", {
        method: "POST",
        body: JSON.stringify({
          reading_type: "bazi",
          input_data: {
            ...baziForm,
            nickname: baziForm.nickname || null,
            gender: baziForm.gender || null,
            birth_place: baziForm.birth_place || null,
          },
        }),
      });
      afterTaskCreated(reading);
    } catch (err) {
      setError(err instanceof Error ? err.message : "提交失败");
      setBusyText("");
    }
  }

  function afterTaskCreated(reading: Reading) {
    setActiveReading(reading);
    setActiveJobId(reading.id);
    setActiveJobType(reading.reading_type);
    setBusyText("");
    void pollReading(reading.id)
      .then(() => loadReadings())
      .catch((err) => setError(err instanceof Error ? err.message : "报告生成失败"))
      .finally(() => setActiveJobId(""));
    void loadReadings();
    void loadQuota();
  }

  async function pollReading(readingId: string) {
    for (let i = 0; i < 80; i += 1) {
      const reading = await apiFetch<Reading>(`/readings/${readingId}`);
      setActiveReading(reading);
      if (reading.status === "completed") return reading;
      if (reading.status === "failed") throw new Error(reading.error_message || "报告生成失败");
      await sleep(2200);
    }
    throw new Error("生成时间较长，请稍后在档案中查看。");
  }

  async function openReading(readingId: string) {
    setError("");
    const reading = await apiFetch<Reading>(`/readings/${readingId}`);
    setActiveReading(reading);
    navigate("archive");
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  async function deleteReading(readingId: string) {
    await apiFetch(`/readings/${readingId}`, { method: "DELETE" });
    if (activeReading?.id === readingId) setActiveReading(null);
    await loadReadings();
  }

  function navigate(view: View) {
    setError("");
    setActiveView(view);
    window.history.pushState(null, "", pathForView(view));
    if (view !== "archive") {
      setActiveReading(null);
    }
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  return (
    <main className="shell">
      <header className="app-topbar">
        <button className="brand compact-button" onClick={() => navigate("home")}>
          <span className="seal">先</span>
          <span>
            <small>CYBER MISTER</small>
            <strong>赛博先生</strong>
          </span>
        </button>
        <nav className="desktop-nav" aria-label="主导航">
          {views.map((view) => (
            <button key={view} className={activeView === view ? "active" : ""} onClick={() => navigate(view)}>
              {view === "home" ? "首页" : view === "archive" ? "档案" : readingMeta[view].name}
            </button>
          ))}
        </nav>
      </header>

      {hasActiveJob ? (
        <button className="job-banner" onClick={() => activeJobId && openReading(activeJobId)}>
          <span className="pulse-dot" />
          <span>先生正在分析{readingMeta[activeJobType].name}，完成后会自动放入档案。你可以继续浏览。</span>
                <strong>去档案</strong>
        </button>
      ) : null}

      {activeView === "home" ? (
        <section className="home-screen">
          <div className="hero-copy">
            <p className="eyebrow">AI 玄学档案 · 娱乐占卜 · 自我反思</p>
            <h1>把日常困惑，交给先生慢慢看。</h1>
            <p>从手相、面相到八字，每一次解读都更贴近生活、学习、事业与关系。</p>
          </div>

          <div className="service-grid">
            {(["palm", "face", "bazi"] as ReadingType[]).map((type) => (
              <button key={type} className="service-card" onClick={() => navigate(type)}>
                <span>已开放</span>
                <strong>{readingMeta[type].name}</strong>
                <em>{readingMeta[type].title}</em>
                <small>{readingMeta[type].description}</small>
              </button>
            ))}
          </div>

          <HomeStats total={readings.length} completed={completedReadings} quota={quota} />
        </section>
      ) : null}

      {activeView === "palm" ? (
        <ImageReadingForm
          type="palm"
          preview={palmPreview}
          busyText={busyText}
          ready={ready}
          error={error}
          quota={quota}
          onPickFile={(event) => pickFile(event, "palm")}
          onSubmit={() => startImageReading("palm")}
          extra={
            <div className="segmented" aria-label="选择左右手">
              {(["left", "right", "unknown"] as HandSide[]).map((side) => (
                <button key={side} className={handSide === side ? "active" : ""} onClick={() => setHandSide(side)}>
                  {handText[side]}
                </button>
              ))}
            </div>
          }
        />
      ) : null}

      {activeView === "face" ? (
        <ImageReadingForm
          type="face"
          preview={facePreview}
          busyText={busyText}
          ready={ready}
          error={error}
          quota={quota}
          onPickFile={(event) => pickFile(event, "face")}
          onSubmit={() => startImageReading("face")}
          extra={null}
        />
      ) : null}

      {activeView === "bazi" ? (
        <BaziFormView
          form={baziForm}
          setForm={setBaziForm}
          busyText={busyText}
          ready={ready}
          error={error}
          quota={quota}
          onSubmit={startBaziReading}
        />
      ) : null}

      {activeView === "archive" ? (
        <section className="archive-screen">
          <div className="archive-head">
            <div>
              <p className="section-label">MISTER ARCHIVE</p>
              <h2>个人玄学档案</h2>
            </div>
            <button className="ghost-action" onClick={() => navigate("home")}>新建解读</button>
          </div>
          <div className="report-list">
            {readings.length ? (
              readings.map((item) => (
                <div key={item.id} className={`archive-item ${item.status === "failed" ? "is-failed" : ""}`}>
                  <button className="archive-open" onClick={() => openReading(item.id)}>
                    <span>
                    <strong>{readingMeta[item.reading_type].name}报告</strong>
                    <small>{formatDate(item.created_at)}</small>
                    {item.overall_summary ? <b>{item.overall_summary}</b> : null}
                    </span>
                  </button>
                  <div className="archive-actions">
                    <em>{statusText[item.status]}</em>
                    <button className="archive-delete" onClick={() => deleteReading(item.id)} aria-label={`删除${readingMeta[item.reading_type].name}报告`}>
                      移除
                    </button>
                  </div>
                </div>
              ))
            ) : (
              <p className="empty">暂无档案。生成第一份报告后会出现在这里。</p>
            )}
          </div>
          {activeReading ? <ReportPanel reading={activeReading} onDelete={() => deleteReading(activeReading.id)} /> : null}
        </section>
      ) : null}

      <nav className="mobile-tabbar" aria-label="移动端导航">
        {views.map((view) => (
          <button key={view} className={activeView === view ? "active" : ""} onClick={() => navigate(view)}>
            <span>{view === "home" ? "⌂" : view === "archive" ? "册" : readingMeta[view].name.slice(0, 1)}</span>
            {view === "home" ? "首页" : view === "archive" ? "档案" : readingMeta[view].name}
          </button>
        ))}
      </nav>
    </main>
  );
}

function ImageReadingForm({
  type,
  preview,
  busyText,
  ready,
  error,
  quota,
  extra,
  onPickFile,
  onSubmit,
}: {
  type: "palm" | "face";
  preview: string;
  busyText: string;
  ready: boolean;
  error: string;
  quota: Quota | null;
  extra: ReactNode;
  onPickFile: (event: ChangeEvent<HTMLInputElement>) => void;
  onSubmit: () => void;
}) {
  const isPalm = type === "palm";
  return (
    <section className="workspace">
      <div className="upload-card">
        <div className="section-label">{readingMeta[type].label}</div>
        <h2>{isPalm ? "上传掌心照片" : "上传正脸照片"}</h2>
        <p>{isPalm ? "掌心完整入镜、光线充足、纹路清晰。左右手不确定可以选“不确定”。" : "请上传单人正脸照，五官无遮挡，光线自然清晰。"}</p>

        <label className={`drop-zone ${preview ? "has-preview" : ""}`}>
          {preview ? (
            <img src={preview} alt={isPalm ? "掌心照片预览" : "正脸照片预览"} />
          ) : (
            <span>
              <strong>选择照片</strong>
              <small>支持 JPG / PNG / WEBP</small>
            </span>
          )}
          <input type="file" accept="image/png,image/jpeg,image/webp" onChange={onPickFile} />
        </label>

        {extra}
        <button className="primary-action" disabled={!ready || Boolean(busyText) || quota?.remaining === 0} onClick={onSubmit}>
          {busyText || (quota?.remaining === 0 ? "今日次数已用完" : "提交分析")}
        </button>
        {error ? <p className="error">{error}</p> : null}
      </div>

      <aside className="side-panel">
        <div className="mini-card">
          <div className="section-label">生成方式</div>
          <h3>提交后可离开等待</h3>
          <p>提交成功后，系统会在后台生成报告。你可以继续看档案，完成后自动刷新。</p>
        </div>
      </aside>
    </section>
  );
}

function BaziFormView({
  form,
  setForm,
  busyText,
  ready,
  error,
  quota,
  onSubmit,
}: {
  form: BaziForm;
  setForm: (form: BaziForm) => void;
  busyText: string;
  ready: boolean;
  error: string;
  quota: Quota | null;
  onSubmit: () => void;
}) {
  return (
    <section className="workspace">
      <div className="upload-card">
        <div className="section-label">BAZI READING</div>
        <h2>填写生辰信息</h2>
        <p>输入出生日期与时间，赛博先生会先排出四柱，再把格局翻译成贴近日常的提醒。</p>

        <div className="form-grid">
          <label className="field">
            <span>昵称</span>
            <input value={form.nickname} onChange={(event) => setForm({ ...form, nickname: event.target.value })} placeholder="可不填" />
          </label>
          <label className="field">
            <span>性别/称谓</span>
            <select value={form.gender} onChange={(event) => setForm({ ...form, gender: event.target.value })}>
              <option value="">不填写</option>
              <option value="female">女</option>
              <option value="male">男</option>
              <option value="other">不限定</option>
            </select>
          </label>
          <label className="field">
            <span>历法</span>
            <select value={form.calendar_type} onChange={(event) => setForm({ ...form, calendar_type: event.target.value as "solar" | "lunar" })}>
              <option value="solar">公历</option>
              <option value="lunar">农历</option>
            </select>
          </label>
          {form.calendar_type === "lunar" ? (
            <label className="checkbox-line">
              <input type="checkbox" checked={form.is_leap_month} onChange={(event) => setForm({ ...form, is_leap_month: event.target.checked })} />
              闰月
            </label>
          ) : null}
          <label className="field">
            <span>出生日期</span>
            <input type="date" value={form.birth_date} onChange={(event) => setForm({ ...form, birth_date: event.target.value })} />
          </label>
          <label className="field">
            <span>出生时间</span>
            <input type="time" value={form.birth_time} disabled={form.time_unknown} onChange={(event) => setForm({ ...form, birth_time: event.target.value })} />
          </label>
          <label className="checkbox-line">
            <input type="checkbox" checked={form.time_unknown} onChange={(event) => setForm({ ...form, time_unknown: event.target.checked })} />
            不确定时辰
          </label>
          <label className="field field-wide">
            <span>出生地</span>
            <input value={form.birth_place} onChange={(event) => setForm({ ...form, birth_place: event.target.value })} placeholder="例如：广东深圳" />
          </label>
        </div>

        <button className="primary-action" disabled={!ready || Boolean(busyText) || quota?.remaining === 0} onClick={onSubmit}>
          {busyText || (quota?.remaining === 0 ? "今日次数已用完" : "提交排盘")}
        </button>
        {error ? <p className="error">{error}</p> : null}
      </div>

      <aside className="side-panel">
        <div className="mini-card">
          <div className="section-label">排盘说明</div>
          <h3>先排盘，再解读</h3>
          <p>后端会先计算四柱、五行和十神线索，再让赛博先生生成更接地气的生活化报告。</p>
        </div>
      </aside>
    </section>
  );
}

function HomeStats({ total, completed, quota }: { total: number; completed: number; quota: Quota | null }) {
  return (
    <div className="home-stats">
      <div>
        <p className="section-label">TODAY STATUS</p>
        <h2>今日解读状态</h2>
      </div>
      <div className="stats">
        <Stat label="今日剩余" value={quota?.remaining ?? 0} />
        <Stat label="每日上限" value={quota?.limit ?? 5} />
        <Stat label="累计报告" value={total} />
        <Stat label="已完成" value={completed} />
      </div>
    </div>
  );
}

function ReportPanel({ reading, onDelete }: { reading: Reading; onDelete: () => void }) {
  const data = reading.report_data;
  const score = useMemo(() => getScore(data), [data]);
  const type = reading.reading_type;
  const handSide = (reading.input_data?.hand_side as HandSide | undefined) || "unknown";
  if (!data) {
    return (
      <section className="report-panel">
        <h3>{statusText[reading.status]}</h3>
        <p>{reading.error_message || "先生正在整理报告。"}</p>
        <button className="delete-action" onClick={onDelete}>删除这份报告</button>
      </section>
    );
  }

  return (
    <section className="report-panel">
      <div className="report-hero">
        <div>
          <p className="section-label">
            {readingMeta[type].label}
            {type === "palm" ? ` · ${handText[handSide]}` : ""}
          </p>
          <h3>赛博先生{readingMeta[type].name}报告</h3>
          <p>{data.overall_summary}</p>
        </div>
        <div className="score">
          <strong>{score}</strong>
          <span>/100</span>
        </div>
      </div>

      <div className="keywords">
        {data.lucky_keywords.map((word) => (
          <span key={word}>{word}</span>
        ))}
      </div>

      {type === "bazi" ? <BaziChartPanel chart={getBaziChart(reading)} /> : null}

      <div className="dimension-grid">
        {data.dimensions.map((dimension, index) => (
          <DimensionCard key={`${dimension.name}-${index}`} dimension={dimension} index={index} />
        ))}
      </div>

      <div className="summary-grid">
        <SummaryList title="优势倾向" items={data.strengths} />
        <SummaryList title="需要留意" items={data.challenges} />
        <SummaryList title="近期建议" items={data.suggestions} />
      </div>

      <p className="disclaimer">{data.disclaimer}</p>
      <button className="delete-action" onClick={onDelete}>删除这份报告</button>
    </section>
  );
}

function BaziChartPanel({ chart }: { chart: BaziChart | null }) {
  if (!chart) return null;
  const pillars = chart.pillars || {};
  const wuxing = chart.wuxing_balance || {};
  const pillarItems = [
    ["年柱", pillars.year],
    ["月柱", pillars.month],
    ["日柱", pillars.day],
    ["时柱", pillars.time],
  ];

  return (
    <section className="bazi-chart">
      <div className="bazi-chart-head">
        <div>
          <p className="section-label">CHART</p>
          <h4>排盘核心</h4>
        </div>
        <span>{chart.time_unknown ? "时辰不详" : chart.birth_time || "已记录时辰"}</span>
      </div>
      <div className="pillar-row">
        {pillarItems.map(([label, value]) => (
          <div className="pillar" key={label}>
            <span>{label}</span>
            <strong>{value || "-"}</strong>
          </div>
        ))}
      </div>
      <div className="chart-facts">
        <span>公历：{chart.solar_date || "-"}</span>
        <span>农历：{chart.lunar_date || "-"}</span>
        <span>日主：{chart.day_master || "-"}</span>
        {chart.birth_place ? <span>出生地：{chart.birth_place}</span> : null}
      </div>
      <div className="wuxing-bars">
        {(["木", "火", "土", "金", "水"] as const).map((name) => {
          const value = wuxing[name] || 0;
          return (
            <div className="wuxing-bar" key={name}>
              <span>{name}</span>
              <i style={{ width: `${Math.max(8, value * 14)}%` }} />
              <em>{value}</em>
            </div>
          );
        })}
      </div>
    </section>
  );
}

function DimensionCard({ dimension, index }: { dimension: Dimension; index: number }) {
  return (
    <article className="dimension-card">
      <div className="dimension-head">
        <span>0{index + 1}</span>
        <strong>{dimension.name}</strong>
        <em>{Math.round(dimension.confidence * 100)}%</em>
      </div>
      <p>{dimension.interpretation}</p>
      <div className="observations">
        {dimension.observations.map((item) => (
          <span key={item}>{item}</span>
        ))}
      </div>
      <div className="advice">先生建议：{dimension.advice}</div>
    </article>
  );
}

function getBaziChart(reading: Reading): BaziChart | null {
  const chart = reading.input_data?.chart;
  if (!chart || typeof chart !== "object" || Array.isArray(chart)) return null;
  return chart as BaziChart;
}

function SummaryList({ title, items }: { title: string; items: string[] }) {
  return (
    <article className="summary-list">
      <h4>{title}</h4>
      {items.map((item) => (
        <p key={item}>{item}</p>
      ))}
    </article>
  );
}

function Stat({ label, value }: { label: string; value: number }) {
  return (
    <div className="stat">
      <strong>{value}</strong>
      <span>{label}</span>
    </div>
  );
}

function getScore(data?: ReportData | null) {
  if (!data?.dimensions?.length) return 68;
  const average = data.dimensions.reduce((sum, item) => sum + item.confidence, 0) / data.dimensions.length;
  const quality = data.quality_check?.confidence || 0.7;
  return Math.max(60, Math.min(96, Math.round((average * 0.65 + quality * 0.35) * 100)));
}

function formatDate(value: string) {
  return value.replace("T", " ").slice(0, 16);
}

function readViewFromPath(fallback: View): View {
  if (typeof window === "undefined") return "home";
  const segment = window.location.pathname.replace(/^\/+/, "").split("/")[0] || "home";
  return views.includes(segment as View) ? (segment as View) : fallback;
}

function pathForView(view: View) {
  return view === "home" ? "/" : `/${view}`;
}

function sleep(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
