/**
 * 电商套图工作台 - Side Panel
 *
 * 布局：顶栏 + 目标平台
 *   ├─ 左 01 商品信息 ｜ 右 02 采集图片（两列等高，采集阶段）
 *   ├─ 03 出图方案（整行：方案列表 + AI 智能规划 + 风格 + 一键生成）
 *   └─ 04 生成结果（整行）
 *
 * 流程：采集页面 → 编辑/勾选 → AI 规划或用默认方案 → 一键生成 → 导出 ZIP
 */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { App as AntApp, ConfigProvider, Popover, Progress } from 'antd';
import { SettingOutlined, DownloadOutlined, ThunderboltOutlined } from '@ant-design/icons';
import type { ScanResult, ImageMaterial } from '../../src/collector/scan';
import {
  buildGeneratePayload, suiteZipUrl,
  DEFAULT_PLAN, PLATFORM_OPTIONS, PLATFORM_SPECS, STYLE_SET_OPTIONS,
  type PlanItem, type SuiteInfo,
} from '../../src/api/client';
import { loadSettings, saveSettings, type BackendSettings } from '../../src/storage/settings';

/** 数据来源 → 展示含义 */
const SOURCE_LABELS: Record<string, string> = {
  state: '页面数据',
  ssr: '页面数据',
  jsonld: '结构化数据',
  api: '站内接口',
  dom: 'DOM解析',
  mixed: '混合来源',
};

/** 平台 → 展示名 */
const PLATFORM_LABELS: Record<string, string> = {
  ozon: 'Ozon',
  '1688': '1688',
  taobao: '淘宝/天猫',
};

/** 在当前活动 tab 执行采集（content script 已把入口挂到 window） */
async function scanActiveTab(): Promise<ScanResult> {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  if (!tab?.id) throw new Error('未找到活动标签页');
  const [res] = await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: () => (window as any).__SuiteCollector?.scan?.() ?? null,
  });
  const r = (res?.result ?? null) as ScanResult | null;
  if (!r) throw new Error('采集失败：页面不支持或内容脚本未就绪，请刷新页面后重试');
  return r;
}

function send<T>(action: string, payload: Record<string, unknown>): Promise<T> {
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage({ action, ...payload }, (res: { ok: boolean; data?: T; error?: string }) => {
      if (chrome.runtime.lastError) return reject(new Error(chrome.runtime.lastError.message));
      if (!res?.ok) return reject(new Error(res?.error || '后台请求失败'));
      resolve(res.data as T);
    });
  });
}

// ── 小组件 ─────────────────────────────────────────────────────────────────

const Section: React.FC<{ no: string; title: string; extra?: React.ReactNode; children: React.ReactNode }> =
  ({ no, title, extra, children }) => (
    <div className="section">
      <div className="section-head">
        <span className="section-no">{no}</span>
        <span className="section-title">{title}</span>
        {extra && <span className="section-extra">{extra}</span>}
      </div>
      {children}
    </div>
  );

const Field: React.FC<{ label: string; children: React.ReactNode }> = ({ label, children }) => (
  <div className="field">
    <label>{label}</label>
    {children}
  </div>
);

/** 数量加减器 */
const Stepper: React.FC<{ value: number; onChange: (v: number) => void }> = ({ value, onChange }) => (
  <span className="stepper">
    <button className="step-btn" disabled={value <= 0} onClick={() => onChange(Math.max(0, value - 1))}>−</button>
    <span className="step-num">{value}</span>
    <button className="step-btn" disabled={value >= 5} onClick={() => onChange(Math.min(5, value + 1))}>＋</button>
  </span>
);

const App: React.FC = () => {
  const { modal } = AntApp.useApp();

  // 采集
  const [scanning, setScanning] = useState(false);
  const [result, setResult] = useState<ScanResult | null>(null);
  const [selectedKeys, setSelectedKeys] = useState<Set<string>>(new Set());
  const [titleEdit, setTitleEdit] = useState('');
  const [descEdit, setDescEdit] = useState('');
  const [paramsOpen, setParamsOpen] = useState(false);

  // 服务端
  const [settings, setSettings] = useState<BackendSettings>({ baseUrl: 'http://127.0.0.1:3300', token: '' });

  // 出图方案
  const [platform, setPlatform] = useState<'ozon' | 'wb' | 'cn'>('cn');
  const [styleSet, setStyleSet] = useState(1);
  const [plan, setPlan] = useState<PlanItem[]>(DEFAULT_PLAN.map(p => ({ ...p })));
  const [planSource, setPlanSource] = useState<'default' | 'ai'>('default');
  const [planSummary, setPlanSummary] = useState('');
  const [planning, setPlanning] = useState(false);

  // 生成
  const [suite, setSuite] = useState<SuiteInfo | null>(null);
  const [generating, setGenerating] = useState(false);
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);

  // 图片放大预览
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);

  useEffect(() => {
    loadSettings().then(setSettings);
    return () => { if (pollRef.current) clearInterval(pollRef.current); };
  }, []);

  const price = result?.texts.find(t => t.kind === 'price')?.content ?? '';
  const brand = result?.texts.find(t => t.kind === 'brand')?.content ?? '';
  const paramPairs = result?.texts.find(t => t.kind === 'params')?.pairs ?? [];

  const handleScan = async () => {
    setScanning(true);
    try {
      const r = await scanActiveTab();
      setResult(r);
      setSuite(null);
      setParamsOpen(false);
      // 默认全选主图 + SKU 图（SKU 图带规格名，AI 规划的 variant 绑定要用）
      const keys = new Set(r.images.filter(i => i.groupKey === 'main' || i.groupKey === 'sku').map(i => i.key));
      setSelectedKeys(keys);
      setTitleEdit(r.texts.find(t => t.kind === 'title')?.content ?? '');
      setDescEdit(r.texts.find(t => t.kind === 'desc')?.content ?? '');
    } catch (e) {
      modal.error({ title: '采集失败', content: e instanceof Error ? e.message : String(e), okText: '知道了' });
    } finally {
      setScanning(false);
    }
  };

  const stopPolling = () => { if (pollRef.current) { clearInterval(pollRef.current); pollRef.current = null; } };

  const pollSuite = useCallback((suiteId: string) => {
    stopPolling();
    pollRef.current = setInterval(async () => {
      try {
        const s = await send<SuiteInfo>('getSuite', { baseUrl: settings.baseUrl, token: settings.token, suiteId });
        setSuite(s);
        if (['done', 'partial', 'failed'].includes(s.status)) {
          stopPolling();
          setGenerating(false);
          if (s.status === 'partial') modal.warning({ title: '部分生成失败', content: '可重试或更换风格重新生成', okText: '知道了' });
          if (s.status === 'failed') modal.error({ title: '生成失败', content: s.error || '未知错误', okText: '知道了' });
        }
      } catch (e) {
        stopPolling();
        setGenerating(false);
      }
    }, 3000);
  }, [settings.baseUrl, settings.token, modal]);

  /** 当前编辑后的文本素材（规划与生成共用） */
  const editedTexts = () => {
    if (!result) return [];
    const orig = (kind: string) => result.texts.find(t => t.kind === kind);
    const texts: Array<{ kind: string; content: string; pairs?: Array<{ key: string; value: string }> | null }> = [];
    const title = titleEdit || orig('title')?.content || '';
    const desc = descEdit || orig('desc')?.content || '';
    if (title) texts.push({ kind: 'title', content: title });
    if (orig('price')?.content) texts.push({ kind: 'price', content: orig('price')!.content });
    if (orig('brand')?.content) texts.push({ kind: 'brand', content: orig('brand')!.content });
    if ((orig('params')?.pairs ?? []).length) texts.push({ kind: 'params', content: '', pairs: orig('params')!.pairs });
    if (orig('selling_point')?.content) texts.push({ kind: 'selling_point', content: orig('selling_point')!.content });
    if (desc) texts.push({ kind: 'desc', content: desc });
    return texts;
  };

  /** AI 智能规划出图方案 */
  const handlePlan = async () => {
    if (!result) return modal.warning({ title: '请先采集商品页' });
    setPlanning(true);
    try {
      const skuVariants = Array.from(new Set(
        result.images.filter(i => i.groupKey === 'sku' && i.variantName).map(i => i.variantName!)
      ));
      const data = await send<{ summary: string; items: PlanItem[] }>('planSuite', {
        baseUrl: settings.baseUrl, token: settings.token,
        payload: {
          texts: editedTexts(),
          sku_variants: skuVariants,
          image_stats: result.stats,
          platform,
        },
      });
      setPlan(data.items);
      setPlanSource('ai');
      setPlanSummary(data.summary);
      const total = data.items.reduce((s, i) => s + i.count, 0);
      modal.info({
        title: 'AI 方案已生成',
        content: `${data.summary}（共 ${total} 张）。可逐项调整数量，0 即不生成。`,
        okText: '好的',
      });
    } catch (e) {
      modal.error({ title: '规划失败', content: e instanceof Error ? e.message : String(e), okText: '知道了' });
    } finally {
      setPlanning(false);
    }
  };

  const totalPlanned = plan.reduce((s, i) => s + i.count, 0);
  const doneCount = suite?.images.filter(i => i.status === 'ok').length ?? 0;
  const suiteTotal = suite?.images.length ?? totalPlanned;

  const handleGenerate = () => {
    if (!result) return;
    if (selectedKeys.size === 0) return modal.warning({ title: '请先在采集图片区勾选参考图' });
    if (totalPlanned === 0) return modal.warning({ title: '出图方案的张数都是 0' });
    const spec = PLATFORM_SPECS[platform];
    modal.confirm({
      title: '生成电商套图',
      content: `目标平台「${spec.label}」（${spec.lang}文案 · ${spec.ratio}），风格「${STYLE_SET_OPTIONS.find(s => s.value === styleSet)?.label}」，共 ${totalPlanned} 张、参考图 ${selectedKeys.size} 张。生成需要几分钟，可在下方查看进度。`,
      okText: '开始生成', cancelText: '取消',
      onOk: async () => {
        setGenerating(true);
        setSuite(null);
        try {
          const payload = buildGeneratePayload(
            result, selectedKeys,
            { title: titleEdit, desc: descEdit },
            { style_set: styleSet, plan: plan.filter(p => p.count > 0), platform },
          );
          const { suite_id } = await send<{ suite_id: string }>('generateSuite', {
            baseUrl: settings.baseUrl, token: settings.token, payload,
          });
          pollSuite(suite_id);
        } catch (e) {
          setGenerating(false);
          modal.error({ title: '提交失败', content: e instanceof Error ? e.message : String(e), okText: '知道了' });
        }
      },
    });
  };

  const handleExport = () => {
    if (!suite) return;
    chrome.tabs.create({ url: suiteZipUrl(settings.baseUrl, suite.id) });
  };

  const toggleKey = (key: string) => {
    const next = new Set(selectedKeys);
    if (next.has(key)) next.delete(key); else next.add(key);
    setSelectedKeys(next);
  };

  const groupImages = (groupKey: string): ImageMaterial[] =>
    result?.images.filter(i => i.groupKey === groupKey) ?? [];

  const toggleGroup = (groupKey: string, on: boolean) => {
    const next = new Set(selectedKeys);
    groupImages(groupKey).forEach(i => on ? next.add(i.key) : next.delete(i.key));
    setSelectedKeys(next);
  };

  const setPlanCount = (idx: number, count: number) => {
    setPlan(prev => prev.map((p, i) => i === idx ? { ...p, count } : p));
  };

  /** 源站图防盗链时的兜底：走服务端图片代理 */
  const proxied = (u: string) =>
    `${settings.baseUrl.replace(/\/$/, '')}/api/proxy-image?url=${encodeURIComponent(u)}`;

  /** 缩略图三级降级：thumbUrl → 原图 → 服务端代理 */
  const onThumbError = (e: React.SyntheticEvent<HTMLImageElement>, url: string) => {
    const el = e.currentTarget;
    if (el.dataset.step === '1') { el.dataset.step = '2'; el.src = url; }
    else if (el.dataset.step === '2') { el.dataset.step = '3'; el.src = proxied(url); }
  };

  const settingsPopup = (
    <div style={{ width: 260 }}>
      <Field label="后端地址">
        <input
          value={settings.baseUrl}
          onChange={(e) => setSettings({ ...settings, baseUrl: e.target.value })}
          onBlur={() => saveSettings(settings)}
        />
      </Field>
      <Field label="Token（可选）">
        <input
          value={settings.token}
          onChange={(e) => setSettings({ ...settings, token: e.target.value })}
          onBlur={() => saveSettings(settings)}
        />
      </Field>
    </div>
  );

  return (
    <div className="page">
      {/* ── 顶栏 ── */}
      <div className="topbar">
        <div className="logo">套</div>
        <div>
          <h1>电商套图工作台</h1>
          <div className="sub">商品采集 · 套图生成 · 一键导出</div>
        </div>
        <div className="spacer" />
        <Popover content={settingsPopup} title="服务端设置" trigger="click" placement="bottomRight">
          <button className="icon-btn" title="服务端设置"><SettingOutlined /></button>
        </Popover>
        <button className="btn btn-primary" disabled={scanning} onClick={handleScan}>
          {scanning ? '采集中…' : '快速采集'}
        </button>
      </div>

      {/* ── 目标平台切换（决定文案语言 + 图片比例）── */}
      <div className="platform-bar">
        <span className="platform-label">目标平台</span>
        <div className="pills">
          {PLATFORM_OPTIONS.map(p => (
            <span
              key={p.value}
              className={`pill ${platform === p.value ? 'on' : ''}`}
              onClick={() => setPlatform(p.value)}
            >{p.label}</span>
          ))}
        </div>
        <span className="platform-spec">
          {PLATFORM_SPECS[platform].lang}文案 · {PLATFORM_SPECS[platform].ratio} 图片
        </span>
      </div>

      {/* ── 采集区：左信息 / 右图片，两列等高 ── */}
      <div className="two-col">
        <Section
          no="01"
          title="商品信息"
          extra={result
            ? `${PLATFORM_LABELS[result.platform] ?? result.platform} · ${SOURCE_LABELS[result.source] ?? result.source}`
            : undefined}
        >
          {!result ? (
            <div className="empty">点击右上角「快速采集」抓取当前商品页</div>
          ) : (
            <>
              <Field label="标题">
                <input value={titleEdit} onChange={(e) => setTitleEdit(e.target.value)} />
              </Field>
              <div style={{ display: 'flex', gap: 8 }}>
                <div style={{ flex: 1 }}>
                  <Field label="价格">
                    <input value={price} readOnly style={{ color: 'var(--text-2)' }} />
                  </Field>
                </div>
                <div style={{ flex: 1 }}>
                  <Field label="品牌">
                    <input value={brand} readOnly style={{ color: 'var(--text-2)' }} />
                  </Field>
                </div>
              </div>
              {paramPairs.length > 0 && (
                <div className="field">
                  <label style={{ cursor: 'pointer' }} onClick={() => setParamsOpen(v => !v)}>
                    规格 / 参数（{paramPairs.length} 项）{paramsOpen ? ' ▴' : ' ▾'}
                  </label>
                  {paramsOpen && (
                    <table className="kv-table">
                      <tbody>
                        {paramPairs.slice(0, 30).map((p, i) => (
                          <tr key={i}><td className="k">{p.key}</td><td>{p.value}</td></tr>
                        ))}
                      </tbody>
                    </table>
                  )}
                </div>
              )}
              <Field label="商品描述（用于生成图内文案）">
                <textarea rows={6} value={descEdit} onChange={(e) => setDescEdit(e.target.value)} />
              </Field>
              {result.warnings.length > 0 && (
                <div className="warn-box">{result.warnings.map((w, i) => <div key={i}>{w}</div>)}</div>
              )}
            </>
          )}
        </Section>

        <Section
          no="02"
          title="采集图片"
          extra={result ? `已选 ${selectedKeys.size} / ${result.images.length}` : undefined}
        >
          {!result ? (
            <div className="empty">采集后在此勾选图片</div>
          ) : (
            <div className="img-groups">
              {['main', 'sku', 'detail'].map(g => groupImages(g).length > 0 && (
                <div key={g} style={{ marginBottom: 10 }}>
                  <div className="group-head">
                    <span className="name">
                      {g === 'main' ? '主图' : g === 'sku' ? 'SKU图片' : '详情图'}
                    </span>
                    <span className="count">{groupImages(g).length}</span>
                    <span
                      className="mini-check"
                      onClick={() => {
                        const all = groupImages(g).every(i => selectedKeys.has(i.key));
                        toggleGroup(g, !all);
                      }}
                    >
                      {groupImages(g).every(i => selectedKeys.has(i.key)) ? '取消全选' : '全选'}
                    </span>
                  </div>
                  <div className="img-grid">
                    {groupImages(g).map(img => {
                      const on = selectedKeys.has(img.key);
                      return (
                        <div key={img.key} className={`img-cell ${on ? 'on' : ''}`}
                          title="点击放大预览，勾选圆点选择图片"
                          onClick={() => setPreviewUrl(img.url)}>
                          <img
                            src={img.thumbUrl || img.url}
                            referrerPolicy="no-referrer"
                            data-step="1"
                            onError={(e) => onThumbError(e, img.url)}
                          />
                          <span
                            className="tick"
                            onClick={(e) => { e.stopPropagation(); toggleKey(img.key); }}
                          >✓</span>
                          {img.variantName && <span className="variant">{img.variantName}</span>}
                        </div>
                      );
                    })}
                  </div>
                </div>
              ))}
            </div>
          )}
        </Section>
      </div>

      {/* ── 出图方案（整行）── */}
      <Section
        no="03"
        title="出图方案"
        extra={
          <span>
            {planSource === 'ai' ? <span className="ai-tag">AI 方案</span> : '默认方案'}
            {' '}共 <b style={{ color: 'var(--primary)' }}>{totalPlanned}</b> 张
          </span>
        }
      >
        <div className="plan-list">
          {plan.map((p, idx) => (
            <div key={idx} className={`plan-row ${p.count === 0 ? 'off' : ''}`}>
              <div className="plan-main">
                <span className="plan-title">{p.title}</span>
                {p.variant_name && <span className="variant-chip">{p.variant_name}</span>}
                {p.detail && <span className="plan-detail" title={p.detail}>{p.detail}</span>}
              </div>
              <Stepper value={p.count} onChange={(v) => setPlanCount(idx, v)} />
            </div>
          ))}
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, margin: '10px 0' }}>
          <button className="btn" disabled={!result || planning} onClick={handlePlan}>
            <ThunderboltOutlined /> {planning ? '规划中…' : 'AI 智能规划'}
          </button>
          {planSource === 'ai' && (
            <button
              className="btn btn-sm"
              onClick={() => { setPlan(DEFAULT_PLAN.map(p => ({ ...p }))); setPlanSource('default'); setPlanSummary(''); }}
            >恢复默认方案</button>
          )}
          <span className="hint" style={{ flex: 1 }}>
            {planSummary || '方案与张数由规划器根据商品信息自动决定，可手动微调，0 即不生成'}
          </span>
        </div>

        <div className="divider" />
        <div className="field">
          <label>视觉风格</label>
          <div className="pills">
            {STYLE_SET_OPTIONS.map(s => (
              <span
                key={s.value}
                className={`pill ${styleSet === s.value ? 'on' : ''}`}
                onClick={() => setStyleSet(s.value)}
              >{s.label}</span>
            ))}
          </div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 4 }}>
          <button
            className="btn btn-primary" disabled={!result || generating || selectedKeys.size === 0 || totalPlanned === 0}
            onClick={handleGenerate}
          >
            {generating ? '生成中…' : `一键生成（${totalPlanned} 张）`}
          </button>
          {generating && (
            <div style={{ flex: 1 }}>
              <Progress
                percent={suiteTotal ? Math.round(doneCount / suiteTotal * 100) : 0}
                size="small" status="active" format={() => `${doneCount}/${suiteTotal}`}
              />
            </div>
          )}
        </div>
      </Section>

      {/* ── 生成结果（整行）── */}
      <Section
        no="04"
        title="生成结果"
        extra={
          suite && ['done', 'partial'].includes(suite.status) && (
            <button className="btn btn-sm" onClick={handleExport}>
              <DownloadOutlined /> 导出 ZIP
            </button>
          )
        }
      >
        {!suite ? (
          <div className="empty">生成后在此查看与导出</div>
        ) : (
          <>
            <div style={{ marginBottom: 8 }} className="hint">
              状态：<b style={{ color: suite.status === 'done' ? 'var(--green)' : suite.status === 'failed' ? 'var(--red)' : 'var(--primary)' }}>
                {suite.status === 'running' ? '生成中' : suite.status === 'done' ? '完成' : suite.status === 'partial' ? '部分失败' : suite.status === 'pending' ? '排队中' : '失败'}
              </b>
              {' '}· {PLATFORM_SPECS[suite.platform]?.label ?? suite.platform}
              {' '}· {PLATFORM_SPECS[suite.platform]?.lang ?? suite.lang}文案 · {suite.ratio}
              {' '}· 风格「{STYLE_SET_OPTIONS.find(s => s.value === suite.style_set)?.label}」
            </div>
            <div className="result-grid">
              {suite.images.map(img => (
                <div
                  key={img.type_id + img.name}
                  className={`result-cell ${img.status !== 'ok' ? 'fail' : ''}`}
                  title={img.error || img.name}
                  style={{ cursor: img.status === 'ok' ? 'zoom-in' : 'default' }}
                  onClick={() => img.status === 'ok' && setPreviewUrl(img.url)}
                >
                  {img.status === 'ok' ? (
                    <img src={img.url} referrerPolicy="no-referrer" />
                  ) : (
                    <div style={{ aspectRatio: suite.ratio === '3:4' ? '3/4' : '1', background: 'var(--card-soft)' }} />
                  )}
                  {img.status !== 'ok' && <span className="fail-tag">{img.status === 'failed' ? '✗' : '…'}</span>}
                  <div className="cap">{img.name}</div>
                </div>
              ))}
            </div>
            {suite.error && <div className="warn-box">{suite.error}</div>}
          </>
        )}
      </Section>

      {/* ── 图片放大预览 ── */}
      {previewUrl && (
        <div className="lightbox" onClick={() => setPreviewUrl(null)}>
          <img src={previewUrl} referrerPolicy="no-referrer" onClick={(e) => e.stopPropagation()} />
          <span className="lightbox-tip">点击任意处关闭</span>
        </div>
      )}
    </div>
  );
};

const Root: React.FC = () => (
  <ConfigProvider
    theme={{
      token: {
        colorPrimary: '#8b5cf6',
        colorLink: '#8b5cf6',
        borderRadius: 8,
        fontFamily: "Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif",
      },
    }}
  >
    <AntApp>
      <App />
    </AntApp>
  </ConfigProvider>
);

createRoot(document.getElementById('root')!).render(<Root />);
