import { useEffect, useRef, useState } from 'react';
import { createModel, deleteModel, fetchModels, fetchScrapeJob, fetchScrapeJobs, fetchSchedule, postScrape, updateSchedule } from '../api';
import type { Model, Schedule } from '../api';
import type { ScrapeJob, ScrapeJobDetail } from '../types';
import './Scraper.css';

function PriceCard({ result }: { result: NonNullable<ScrapeJobDetail['results']>[number] }) {
  const { model_info, rate_limits, tool_prices, prices } = result;

  return (
    <div className="price-card">
      <div className="price-card-title">{result.model_name}</div>
      <div className="price-card-url">{result.url}</div>

      {/* 模型信息 */}
      {model_info && (
        <div className="info-section">
          <div className="info-section-title">模型信息</div>
          {model_info.display_tags && model_info.display_tags.length > 0 && (
            <div className="tag-row">
              {model_info.display_tags.map(t => <span key={t} className="tag">{t}</span>)}
            </div>
          )}
          {model_info.description && (
            <div className="info-desc">{model_info.description}</div>
          )}
          {(model_info.input_modalities?.length || model_info.output_modalities?.length) ? (
            <div className="modality-row">
              {model_info.input_modalities?.length ? (
                <span className="modality">输入：{model_info.input_modalities.join(' / ')}</span>
              ) : null}
              {model_info.output_modalities?.length ? (
                <span className="modality">输出：{model_info.output_modalities.join(' / ')}</span>
              ) : null}
            </div>
          ) : null}
          {model_info.features && (
            <div className="feature-grid">
              {Object.entries(model_info.features).map(([k, v]) => (
                <span key={k} className={`feature-item ${v ? 'feature-item--on' : 'feature-item--off'}`}>
                  {v ? '✓' : '✗'} {k}
                </span>
              ))}
            </div>
          )}
        </div>
      )}

      {/* 限流与上下文 */}
      {rate_limits && Object.keys(rate_limits).length > 0 && (
        <div className="info-section">
          <div className="info-section-title">限流与上下文</div>
          <div className="kv-grid">
            {Object.entries(rate_limits).map(([k, v]) => (
              <div key={k} className="kv-item">
                <span className="kv-key">{k}</span>
                <span className="kv-val">{v ?? '-'}</span>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* 工具调用价格 */}
      {tool_prices && tool_prices.length > 0 && (
        <div className="info-section">
          <div className="info-section-title">工具调用价格</div>
          {tool_prices.map((t, i) => (
            <div key={i} className="price-entry">
              <span className="price-key">{t.label}</span>
              <span className="price-val">
                {t.price === 0 ? '免费' : `${t.price} ${t.unit ?? '元/千次'}`}
                {t.note ? <span className="price-note"> ({t.note})</span> : null}
              </span>
            </div>
          ))}
        </div>
      )}

      {/* Token 价格 */}
      {Object.keys(prices).length > 0 && (
        <div className="info-section">
          <div className="info-section-title">Token 价格</div>
          {Object.entries(prices).map(([tier, val]) => (
            <div key={tier} className="price-entry">
              <span className="price-key">{tier}</span>
              <span className="price-val">{JSON.stringify(val)}</span>
            </div>
          ))}
        </div>
      )}

      <div className="price-time">爬取时间：{new Date(result.scraped_at).toLocaleString()}</div>
    </div>
  );
}

export function Scraper() {
  const [models, setModels] = useState<Model[]>([]);
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [showAdd, setShowAdd] = useState(false);
  const [newName, setNewName] = useState('');
  const [newUrl, setNewUrl] = useState('');
  const [addError, setAddError] = useState<string | null>(null);

  const [schedule, setSchedule] = useState<Schedule | null>(null);
  const [scheduleEdit, setScheduleEdit] = useState({ interval_days: 1, start_hour: 2 });
  const [scheduleSaving, setScheduleSaving] = useState(false);

  const [submitting, setSubmitting] = useState(false);
  const [expandedJobs, setExpandedJobs] = useState<Record<string, ScrapeJobDetail>>({});
  const [history, setHistory] = useState<ScrapeJob[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [historyPage, setHistoryPage] = useState(1);
  const [historyPageSize, setHistoryPageSize] = useState(10);
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const resultRef = useRef<HTMLDivElement>(null);

  const loadModels = () => fetchModels().then(setModels).catch(() => {});
  const loadHistory = () => fetchScrapeJobs().then(setHistory).catch(() => {});

  useEffect(() => {
    loadModels();
    loadHistory();
    fetchSchedule().then(s => {
      setSchedule(s);
      setScheduleEdit({ interval_days: s.interval_days, start_hour: s.start_hour });
    }).catch(() => {});
  }, []);

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

  const startPolling = (jobId: string) => {
    stopPolling();
    const deadline = Date.now() + 10 * 60 * 1000; // 最多轮询 10 分钟
    pollRef.current = setInterval(async () => {
      if (Date.now() > deadline) {
        stopPolling();
        setExpandedJobs(prev => {
          const job = prev[jobId];
          if (!job || job.status === 'done' || job.status === 'failed') return prev;
          return { ...prev, [jobId]: { ...job, status: 'failed', error: '轮询超时，请刷新页面查看最新状态' } };
        });
        loadHistory();
        return;
      }
      try {
        const detail = await fetchScrapeJob(jobId);
        setExpandedJobs(prev => ({ ...prev, [jobId]: detail }));
        if (detail.status === 'done' || detail.status === 'failed') {
          stopPolling();
          loadHistory();
        }
      } catch { stopPolling(); }
    }, 2000);
  };

  useEffect(() => () => stopPolling(), []);

  const toggleSelect = (id: number) => {
    setSelected(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  };

  const toggleAll = () => {
    if (selected.size === models.length) setSelected(new Set());
    else setSelected(new Set(models.map(m => m.id)));
  };

  const handleScrape = async () => {
    const urls = models.filter(m => selected.has(m.id)).map(m => m.url);
    if (urls.length === 0) return;
    setSubmitting(true);
    setError(null);
    try {
      const job = await postScrape(urls);
      setExpandedJobs(prev => ({ ...prev, [job.job_id]: { ...job, results: undefined } }));
      startPolling(job.job_id);
      loadHistory();
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setSubmitting(false);
    }
  };

  const handleAdd = async () => {
    if (!newName.trim() || !newUrl.trim()) return;
    setAddError(null);
    try {
      await createModel(newName.trim(), newUrl.trim());
      setNewName(''); setNewUrl(''); setShowAdd(false);
      loadModels();
    } catch (e) {
      setAddError(e instanceof Error ? e.message : String(e));
    }
  };

  const handleToggleSchedule = async () => {
    if (!schedule) return;
    setScheduleSaving(true);
    try {
      const updated = await updateSchedule({ ...scheduleEdit, enabled: !schedule.enabled });
      setSchedule(updated);
    } finally { setScheduleSaving(false); }
  };

  const handleSaveSchedule = async () => {
    if (!schedule) return;
    setScheduleSaving(true);
    try {
      const updated = await updateSchedule({ ...scheduleEdit, enabled: schedule.enabled });
      setSchedule(updated);
    } finally { setScheduleSaving(false); }
  };

  const handleDelete = async (id: number) => {
    await deleteModel(id);
    setSelected(prev => { const n = new Set(prev); n.delete(id); return n; });
    loadModels();
  };

  const handleHistoryClick = async (jobId: string) => {
    // 已展开则收起
    if (expandedJobs[jobId]) {
      setExpandedJobs(prev => { const n = { ...prev }; delete n[jobId]; return n; });
      return;
    }
    try {
      const detail = await fetchScrapeJob(jobId);
      setExpandedJobs(prev => ({ ...prev, [jobId]: detail }));
      if (detail.status === 'pending' || detail.status === 'running') startPolling(jobId);
    } catch { setError('加载任务详情失败'); }
  };

  return (
    <div className="scraper-page scraper-layout">
      {/* 左侧：模型列表 */}
      <aside className="model-sidebar">
        <div className="sidebar-header">
          <span className="sidebar-title">模型列表</span>
          <button className="icon-btn" onClick={() => setShowAdd(v => !v)} title="添加模型">＋</button>
        </div>

        {showAdd && (
          <div className="add-form">
            <input className="add-input" placeholder="模型名称" value={newName} onChange={e => setNewName(e.target.value)} />
            <input className="add-input" placeholder="URL" value={newUrl} onChange={e => setNewUrl(e.target.value)} />
            {addError && <div className="add-error">{addError}</div>}
            <div className="add-actions">
              <button className="add-confirm-btn" onClick={handleAdd}>确认添加</button>
              <button className="add-cancel-btn" onClick={() => { setShowAdd(false); setAddError(null); }}>取消</button>
            </div>
          </div>
        )}

        <div className="model-list-header">
          <label className="check-label">
            <input type="checkbox" checked={models.length > 0 && selected.size === models.length} onChange={toggleAll} />
            <span>全选</span>
          </label>
          <span className="selected-count">{selected.size} / {models.length}</span>
        </div>

        <ul className="model-list">
          {models.length === 0 && <li className="empty-msg">暂无模型，点击 ＋ 添加</li>}
          {models.map(m => (
            <li key={m.id} className={`model-item ${selected.has(m.id) ? 'model-item--selected' : ''}`}>
              <label className="check-label">
                <input type="checkbox" checked={selected.has(m.id)} onChange={() => toggleSelect(m.id)} />
                <span className="model-name">{m.name}</span>
              </label>
              <button className="del-btn" onClick={() => handleDelete(m.id)} title="删除">✕</button>
            </li>
          ))}
        </ul>

        <button className="submit-btn scrape-btn" onClick={handleScrape} disabled={submitting || selected.size === 0}>
          {submitting ? '爬取中…' : `▶ 爬取已选 (${selected.size})`}
        </button>

        {/* 定时爬取配置 */}
        {schedule && (
          <div className="schedule-box">
            <div className="schedule-header">
              <span className="schedule-title">定时爬取</span>
              <button
                className={`toggle-btn ${schedule.enabled ? 'toggle-btn--on' : ''}`}
                onClick={handleToggleSchedule}
                disabled={scheduleSaving}
              >
                {schedule.enabled ? '已开启' : '已关闭'}
              </button>
            </div>
            <div className="schedule-row">
              <label className="schedule-label">每隔</label>
              <input
                type="number" min={1} max={365}
                className="schedule-input"
                value={scheduleEdit.interval_days}
                onChange={e => setScheduleEdit(v => ({ ...v, interval_days: Number(e.target.value) }))}
              />
              <span className="schedule-unit">天</span>
            </div>
            <div className="schedule-row">
              <label className="schedule-label">开始时间</label>
              <input
                type="number" min={0} max={23}
                className="schedule-input schedule-input--sm"
                value={scheduleEdit.start_hour}
                onChange={e => setScheduleEdit(v => ({ ...v, start_hour: Number(e.target.value) }))}
              />
              <span className="schedule-unit">时整</span>
            </div>
            <button className="add-confirm-btn" onClick={handleSaveSchedule} disabled={scheduleSaving}>
              保存配置
            </button>
          </div>
        )}
      </aside>

      {/* 右侧：结果区 */}
      <main className="scraper-main">
        <header className="scraper-header" ref={resultRef}>
          <span className="scraper-title">价格爬取</span>
        </header>

        {error && <div className="error-banner">错误：{error}</div>}

        {history.length > 0 && (
          <section className="history-section">
            <div className="section-title">历史记录</div>
            <ul className="history-list">
              {history.slice((historyPage - 1) * historyPageSize, historyPage * historyPageSize).map(job => {
                const expanded = expandedJobs[job.job_id];
                const isOpen = !!expanded;
                return (
                  <li key={job.job_id} className={`history-item history-item--${job.status}`}>
                    <div className="history-row" onClick={() => handleHistoryClick(job.job_id)}>
                      <span className="history-id">{job.job_id.slice(0, 8)}…</span>
                      <span className="history-status">{
                        job.status === 'done' ? '完成' :
                        job.status === 'failed' ? '失败' :
                        job.status === 'running' ? '运行中' : '等待中'
                      }</span>
                      <span className="history-time">{new Date(job.created_at).toLocaleString()}</span>
                      <span className="history-toggle">{isOpen ? '▲' : '▼'}</span>
                    </div>
                    {isOpen && (
                      <div className="history-detail">
                        {expanded.status === 'failed' && (
                          <div className="error-card">
                            <div className="error-card-title">爬取失败</div>
                            <pre className="error-detail">{expanded.error}</pre>
                          </div>
                        )}
                        {(expanded.status === 'pending' || expanded.status === 'running') && (
                          <div className="empty-msg">爬取中，请稍候…</div>
                        )}
                        {expanded.status === 'done' && expanded.results && expanded.results.map(r => (
                          <PriceCard key={r.url} result={r} />
                        ))}
                      </div>
                    )}
                  </li>
                );
              })}
            </ul>
            {/* 分页 */}
            {(() => {
              const totalPages = Math.ceil(history.length / historyPageSize);
              return (
                <div className="pagination">
                  <span className="pagination-info">共 {history.length} 条</span>
                  <span>每页</span>
                  <select className="page-size-select" value={historyPageSize} onChange={e => { setHistoryPageSize(Number(e.target.value)); setHistoryPage(1); }}>
                    {[5, 10, 20, 50].map(n => <option key={n} value={n}>{n}</option>)}
                  </select>
                  <button className="page-btn" disabled={historyPage <= 1} onClick={() => setHistoryPage(p => p - 1)}>上一页</button>
                  <span className="page-num">{historyPage}</span>
                  <button className="page-btn" disabled={historyPage >= totalPages} onClick={() => setHistoryPage(p => p + 1)}>下一页</button>
                </div>
              );
            })()}
          </section>
        )}
      </main>
    </div>
  );
}
