/* Page — Watchlists (multi-list management) */
const { Icon, Sparkline, fmt, fmtVol, sign, PctBadge, TrendBadge } = window.UI;

const DEFAULT_LISTS = [
  { id: "tw-core", name: "台股核心", icon: "tw", syms: ["2330.TW","2317.TW","2454.TW","2308.TW","2603.TW","2412.TW","2882.TW","2891.TW","3008.TW"] },
  { id: "us-tech", name: "美股科技", icon: "us", syms: ["NVDA","AAPL","TSLA","MSFT","AMD","GOOGL"] },
  { id: "ai", name: "AI 概念", icon: "trending-up", syms: ["NVDA","2330.TW","2454.TW","AMD","MSFT","2308.TW"] },
  { id: "fin", name: "金融", icon: "list", syms: ["2882.TW","2891.TW"] },
  { id: "high-vol", name: "今日量爆", icon: "alert", syms: ["2603.TW","2308.TW","NVDA","TSLA"] },
];

/* 更新欄位顯示：把各種 ts 形式統一成 YYYY/MM/DD HH:MM:SS（兩行：日期 / 時間） */
function parseTs(ts) {
  if (!ts) return { date: "—", time: "" };
  if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}/.test(ts)) {
    const [d, t] = ts.split(" ");
    return { date: d.replace(/-/g, "/"), time: t };
  }
  if (/^\d{4}-\d{2}-\d{2}$/.test(ts)) {
    return { date: ts.replace(/-/g, "/"), time: "收盤" };
  }
  if (/^\d{2}:\d{2}:\d{2}$/.test(ts)) {
    const now = new Date();
    const y = now.getFullYear();
    const mo = String(now.getMonth() + 1).padStart(2, "0");
    const da = String(now.getDate()).padStart(2, "0");
    return { date: `${y}/${mo}/${da}`, time: ts };
  }
  return { date: ts, time: "" };
}

const WatchlistsPage = ({ goChart }) => {
  const [lists, setLists] = window.usePersistedState("watchlists", DEFAULT_LISTS);
  const [activeId, setActiveId] = window.usePersistedState("watchlists.activeId", "tw-core");
  const [editingName, setEditingName] = React.useState(null);
  const active = lists.find(l => l.id === activeId) || lists[0];
  const allRows = window.MOCK.WATCHLIST;  /* picker 用：股票宇宙 */
  const [sort, setSort] = React.useState({ k: "pct", dir: -1 });
  const [pickerOpen, setPickerOpen] = React.useState(false);
  const [pickerQ, setPickerQ] = React.useState("");
  React.useEffect(() => { if (pickerOpen) setPickerQ(""); }, [pickerOpen]);

  const [filterOpen, setFilterOpen] = React.useState(false);
  const [filterMa, setFilterMa] = React.useState(() => new Set(["Bullish", "Sideways", "Bearish"]));
  const filterRef = React.useRef(null);
  React.useEffect(() => {
    if (!filterOpen) return;
    const handler = (e) => {
      if (filterRef.current && !filterRef.current.contains(e.target)) setFilterOpen(false);
    };
    document.addEventListener("mousedown", handler);
    return () => document.removeEventListener("mousedown", handler);
  }, [filterOpen]);
  const toggleMa = (k) => setFilterMa(s => {
    const next = new Set(s);
    if (next.has(k)) next.delete(k); else next.add(k);
    return next;
  });

  /* 真實資料：FinMind 日 K + KCStructure */
  const symsKey = active.syms.join(",");
  const [baseRows, setBaseRows] = React.useState(null);
  const [loadErr, setLoadErr] = React.useState(null);

  React.useEffect(() => {
    let cancelled = false;
    setBaseRows(null);
    setLoadErr(null);
    if (!window.WatchlistEngine || active.syms.length === 0) {
      setBaseRows([]);
      return;
    }
    window.WatchlistEngine.resolveRows(active.syms)
      .then((rs) => { if (!cancelled) setBaseRows(rs); })
      .catch((e) => { if (!cancelled) setLoadErr(e.message); });
    return () => { cancelled = true; };
  }, [symsKey]);

  /* 即時報價：盤中 polling，合併到 baseRows */
  const [quotes, setQuotes] = React.useState(new Map());
  React.useEffect(() => {
    if (!window.Intraday || !window.Intraday.isEnabled() || active.syms.length === 0) return;
    const unsub = window.Intraday.subscribeMany(active.syms, (result) => {
      setQuotes(result.quotes);
    });
    return unsub;
  }, [symsKey]);

  /* fallback：FinMind 還沒到貨時用 mock 撐版面 */
  const mockFallback = React.useMemo(() => {
    const set = new Set(active.syms);
    return (window.MOCK.WATCHLIST || []).filter((r) => set.has(r.sym));
  }, [symsKey]);

  /* 全台股 universe name map — 用於 row.name fallback */
  const [nameMap, setNameMap] = React.useState(null);
  React.useEffect(() => {
    if (!window.FinMind || !window.FinMind.getTaiwanUniverse) return;
    window.FinMind.getTaiwanUniverse()
      .then((list) => setNameMap(new Map(list.map((s) => [s.sym, s.name]))))
      .catch(() => {});
  }, []);

  const rows = React.useMemo(() => {
    const base = baseRows || mockFallback;
    const merged = window.WatchlistEngine
      ? window.WatchlistEngine.mergeQuotes(base, quotes)
      : base;
    if (!nameMap) return merged;
    return merged.map((r) => {
      const fallbackName = r.sym.replace(/\.TW$/, "");
      if ((r.name === fallbackName || !r.name) && nameMap.get(r.sym)) {
        return { ...r, name: nameMap.get(r.sym) };
      }
      return r;
    });
  }, [baseRows, mockFallback, quotes, nameMap]);

  const dataReady = baseRows != null;
  const liveQuotes = quotes && quotes.size > 0;

  const filtered = rows.filter(r => filterMa.has(r.ma));
  const MA_ORDER = { Bearish: 0, Sideways: 1, Bullish: 2 };
  const sorted = [...filtered].sort((a, b) => {
    const k = sort.k, d = sort.dir;
    if (k === "ma") return ((MA_ORDER[a.ma] ?? 1) - (MA_ORDER[b.ma] ?? 1)) * d;
    return typeof a[k] === "string" ? a[k].localeCompare(b[k]) * d : (a[k] - b[k]) * d;
  });

  const Th = ({ k, children, right }) => (
    <th onClick={() => setSort({ k, dir: sort.k === k ? -sort.dir : -1 })}
        className={"th-sort" + (right ? " num" : "")}>
      {children}
      {sort.k === k && <span className="sort-arrow">{sort.dir === -1 ? "▼" : "▲"}</span>}
    </th>
  );

  const removeSym = (sym) => {
    const row = rows.find(r => r.sym === sym);
    const label = row ? `${sym} ${row.name}` : sym;
    if (!confirm(`從「${active.name}」移除 ${label}？`)) return;
    setLists(ls => ls.map(l => l.id === activeId ? {...l, syms: l.syms.filter(s => s !== sym)} : l));
  };

  const addList = () => {
    const id = "list-" + Date.now();
    setLists(ls => [...ls, { id, name: "新清單", icon: "list", syms: [] }]);
    setActiveId(id);
    setEditingName(id);
  };

  const renameList = (id, name) => {
    setLists(ls => ls.map(l => l.id === id ? {...l, name} : l));
  };

  const deleteList = (id) => {
    if (lists.length <= 1) return;
    setLists(ls => ls.filter(l => l.id !== id));
    if (activeId === id) setActiveId(lists[0].id);
  };

  const addSyms = (syms) => {
    setLists(ls => ls.map(l => l.id === activeId
      ? {...l, syms: [...new Set([...l.syms, ...syms])]}
      : l));
    setPickerOpen(false);
  };

  return (
    <div className="page watchlists-page">
      <div className="watchlists-grid">
        {/* Left: list of lists */}
        <aside className="surface lists-sidebar">
          <header className="section-head">
            <h2 className="section-title">我的清單</h2>
            <button className="btn primary" onClick={addList}>
              <Icon name="plus" size={13}/> 新增
            </button>
          </header>
          <ul className="lists-list">
            {lists.map(l => (
              <li key={l.id}
                  className={"list-item" + (activeId === l.id ? " active" : "")}
                  onClick={() => setActiveId(l.id)}>
                <Icon name={l.icon} size={14}/>
                {editingName === l.id ? (
                  <input className="input list-name-input"
                    autoFocus
                    defaultValue={l.name}
                    onBlur={(e) => { renameList(l.id, e.target.value); setEditingName(null); }}
                    onKeyDown={(e) => { if (e.key === "Enter") e.target.blur(); }}
                    onClick={(e) => e.stopPropagation()}/>
                ) : (
                  <span className="list-name"
                        onDoubleClick={(e) => { e.stopPropagation(); setEditingName(l.id); }}>
                    {l.name}
                  </span>
                )}
                <span className="dim mono list-count">{l.syms.length}</span>
                <button className="btn ghost icon-btn list-del"
                        title="刪除清單"
                        onClick={(e) => { e.stopPropagation(); deleteList(l.id); }}>
                  <Icon name="x" size={11}/>
                </button>
              </li>
            ))}
          </ul>
          <footer className="lists-footer">
            <button className="btn ghost" style={{width:"100%"}}>
              <Icon name="external" size={12}/> 匯入 CSV
            </button>
          </footer>
        </aside>

        {/* Right: active list rows */}
        <section className="surface watchlist-section">
          <header className="section-head">
            <div className="section-head-l">
              <Icon name={active.icon} size={16}/>
              <h2 className="section-title">{active.name}</h2>
              <span className="dim mono" style={{fontSize:"var(--fs-xs)"}}>{rows.length} 檔</span>
              {!dataReady && active.syms.length > 0 && (
                <span className="pill" style={{fontSize:"var(--fs-xs)"}}>載入日 K…</span>
              )}
              {loadErr && (
                <span className="pill warn" style={{fontSize:"var(--fs-xs)"}} title={loadErr}>載入失敗</span>
              )}
              {liveQuotes && (
                <span className="pill success dot" style={{fontSize:"var(--fs-xs)"}}>即時報價</span>
              )}
            </div>
            <div className="section-head-r">
              <div ref={filterRef} style={{position:"relative"}}>
                <button className={"btn ghost" + (filterMa.size < 3 ? " active" : "")} onClick={() => setFilterOpen(o => !o)}>
                  <Icon name="filter" size={13}/> 篩選
                  {filterMa.size < 3 && (
                    <span className="pill accent" style={{marginLeft:6, fontSize:9, padding:"1px 6px"}}>{filterMa.size}</span>
                  )}
                </button>
                {filterOpen && (
                  <div className="surface" style={{position:"absolute", top:"calc(100% + 6px)", right:0, zIndex:50, minWidth:180, padding:12, display:"flex", flexDirection:"column", gap:4, boxShadow:"0 8px 24px rgba(0,0,0,0.35)"}}>
                    <div className="dim" style={{fontSize:"var(--fs-xs)", marginBottom:6, letterSpacing:0.3}}>均線趨勢</div>
                    {[
                      {key:"Bullish", label:"均線多頭"},
                      {key:"Sideways", label:"盤整"},
                      {key:"Bearish", label:"均線空頭"},
                    ].map(opt => (
                      <label key={opt.key} className={"chk" + (filterMa.has(opt.key) ? " on" : "")}>
                        <input type="checkbox" checked={filterMa.has(opt.key)} onChange={() => toggleMa(opt.key)}/>
                        {opt.label}
                      </label>
                    ))}
                    <div style={{display:"flex", justifyContent:"space-between", marginTop:8, gap:6}}>
                      <button className="btn ghost" style={{fontSize:"var(--fs-xs)", padding:"4px 8px"}}
                              onClick={() => setFilterMa(new Set(["Bullish", "Sideways", "Bearish"]))}>全選</button>
                      <button className="btn ghost" style={{fontSize:"var(--fs-xs)", padding:"4px 8px"}}
                              onClick={() => setFilterMa(new Set())}>清除</button>
                    </div>
                  </div>
                )}
              </div>
              <button className="btn primary" onClick={() => setPickerOpen(true)}>
                <Icon name="plus" size={13}/> 新增股票
              </button>
            </div>
          </header>

          {rows.length === 0 ? (
            <div className="empty-state">
              <div className="empty-icon"><Icon name="list" size={32}/></div>
              <div className="empty-title">這份清單還是空的</div>
              <div className="dim" style={{fontSize:"var(--fs-sm)", marginTop:4}}>從上方按「新增股票」開始建立</div>
              <button className="btn primary" style={{marginTop:14}} onClick={() => setPickerOpen(true)}>
                <Icon name="plus" size={13}/> 新增股票
              </button>
            </div>
          ) : (
            <div className="watchlist-scroll">
              <table className="watchlist-table">
                <thead>
                  <tr>
                    <Th k="sym">代號</Th>
                    <th>名稱</th>
                    <th>市場</th>
                    <Th k="price" right>現價</Th>
                    <Th k="pct" right>漲跌 %</Th>
                    <th style={{textAlign:"right"}}>走勢</th>
                    <Th k="vol" right>成交量</Th>
                    <Th k="volMa" right>量/MA20</Th>
                    <Th k="ma">均線趨勢</Th>
                    <Th k="rsi" right>RSI</Th>
                    <th>更新</th>
                    <th></th>
                  </tr>
                </thead>
                <tbody>
                  {sorted.map(r => (
                    <tr key={r.sym} className="watch-row" onClick={() => { sessionStorage.setItem("chart.navList", JSON.stringify(sorted.map(x => x.sym))); goChart(r.sym); }} data-color-mode={r.market === "US" ? "us" : "tw"}>
                      <td className="mono"><strong>{r.sym}</strong></td>
                      <td>{r.name}</td>
                      <td><span className="pill" style={{fontSize:9}}>{r.market === "TW" ? "TWSE" : "NASDAQ"}</span></td>
                      <td className={"num num-r " + (r.pct >= 0 ? "up" : "down")}>{fmt(r.price, 2)}</td>
                      <td className="num num-r"><PctBadge pct={r.pct}/></td>
                      <td className="spark-cell"><Sparkline values={r.spark} pct={r.pct}/></td>
                      <td className="num num-r mono dim">{fmtVol(r.vol)}</td>
                      <td className={"num num-r " + (r.volMa > 1.5 ? "up" : (r.volMa < 0.7 ? "down" : "dim"))}>{fmt(r.volMa, 2)}×</td>
                      <td><TrendBadge trend={r.ma}/></td>
                      <td className="num num-r mono">
                        <span style={{color: r.rsi >= 70 ? "var(--danger)" : r.rsi >= 50 ? "var(--warning)" : "var(--success)"}}>{fmt(r.rsi, 1)}</span>
                      </td>
                      <td className="dim mono" style={{fontSize:"var(--fs-xs)", lineHeight:1.3, whiteSpace:"nowrap"}}>
                        {(() => { const t = parseTs(r.ts); return (<>
                          <div>{t.date}</div>
                          <div style={{opacity:0.75}}>{t.time}</div>
                        </>); })()}
                      </td>
                      <td>
                        <div className="row-actions">
                          <button className="btn ghost icon-btn" title="開啟 K 線" onClick={(e) => { e.stopPropagation(); sessionStorage.setItem("chart.navList", JSON.stringify(sorted.map(x => x.sym))); goChart(r.sym); }}><Icon name="chart" size={13}/></button>
                          <button className="btn ghost icon-btn row-del" title="從此清單移除"
                            onClick={(e) => { e.stopPropagation(); removeSym(r.sym); }}>
                            <Icon name="x" size={13}/>
                          </button>
                        </div>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </section>
      </div>

      {pickerOpen && (
        <div className="picker-backdrop" onClick={() => setPickerOpen(false)}>
          <div className="picker-modal surface" onClick={(e) => e.stopPropagation()}>
            <header className="section-head">
              <h3 className="section-title">新增股票到「{active.name}」</h3>
              <button className="btn ghost icon-btn" onClick={() => setPickerOpen(false)}>
                <Icon name="x" size={14}/>
              </button>
            </header>
            <div className="picker-search">
              <Icon name="search" size={13}/>
              <input className="input" placeholder="搜尋代號或名稱..." autoFocus
                value={pickerQ}
                onChange={(e) => setPickerQ(e.target.value)}/>
            </div>
            <div className="picker-list">
              {(() => {
                const q = pickerQ.trim().toLowerCase();
                const filtered = allRows.filter(r => !q
                  || r.sym.toLowerCase().includes(q)
                  || r.name.toLowerCase().includes(q));
                if (filtered.length === 0) {
                  return <div style={{padding:"24px 12px", textAlign:"center", color:"var(--text-3)", fontSize:"var(--fs-sm)"}}>
                    找不到符合「{pickerQ}」的股票
                  </div>;
                }
                return filtered.map(r => {
                  const inList = active.syms.includes(r.sym);
                  return (
                    <button key={r.sym} className="picker-row"
                            onClick={() => { if (!inList) addSyms([r.sym]); }}
                            disabled={inList}
                            data-color-mode={r.market === "US" ? "us" : "tw"}
                            style={inList ? { opacity: 0.55, cursor: "default" } : undefined}>
                      <span className="mono" style={{fontWeight:600, minWidth:80}}>{r.sym}</span>
                      <span style={{flex:1}}>{r.name}</span>
                      <span className="pill" style={{fontSize:9}}>{r.market === "TW" ? "TWSE" : "NASDAQ"}</span>
                      <span className={"num mono " + (r.pct >= 0 ? "up" : "down")}>{fmt(r.price, 2)}</span>
                      {inList
                        ? <span style={{display:"inline-flex", alignItems:"center", gap:4, color:"var(--c-up)", fontSize:"var(--fs-xs)"}}>
                            <Icon name="check" size={13}/> 已加入
                          </span>
                        : <Icon name="plus" size={13}/>}
                    </button>
                  );
                });
              })()}
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

window.WatchlistsPage = WatchlistsPage;
window.DEFAULT_WATCHLISTS = DEFAULT_LISTS;
