/* global React */
// 对战助手 (Matcher): 区域 → 天王 → 选首发 → 决策树聚焦 → 查看锁定队伍。
// 跟 iOS MatcherView 同一套逻辑;web 端只读,不写入。

function MatcherPage({ toast }) {
  const [areas, setAreas] = React.useState([]);
  const [npcs, setNpcs] = React.useState([]);          // 全部 NPC 元数据(用 npcId 拿决策树)
  const [lineups, setLineups] = React.useState({});    // area → [group]
  const [trees, setTrees] = React.useState({});        // npcId → monsterId → tree

  const [areaCode, setAreaCode] = React.useState(null);
  const [npcName, setNpcName] = React.useState(null);
  const [selected, setSelected] = React.useState([]);   // 已选宝可梦名字列表
  const [lockedView, setLockedView] = React.useState(null); // 点"查看队伍 N"展开的 lineup ids

  React.useEffect(() => {
    Promise.all([
      window.API.areas(),
      window.API.npcs(),
      window.API.lineups(),
      window.API.decisionTrees(),
    ]).then(([a, n, l, t]) => {
      setAreas(Array.isArray(a) ? a : []);
      setNpcs(Array.isArray(n) ? n : []);
      setLineups(l || {});
      setTrees(t || {});
      // 默认选第一个有数据的区域
      const first = (Array.isArray(a) ? a : []).find((x) => (l && l[x.code]?.length));
      if (first && !areaCode) setAreaCode(first.code);
    }).catch(() => {});
  }, []);

  const groupsInArea = React.useMemo(
    () => (areaCode ? (lineups[areaCode] || []) : []),
    [areaCode, lineups]
  );

  // 切区域时,自动选第一个 NPC,清空已选
  React.useEffect(() => {
    if (!areaCode) return;
    setSelected([]); setLockedView(null);
    const first = groupsInArea[0]?.npcName || null;
    setNpcName(first);
  }, [areaCode]);

  const currentNpc = React.useMemo(
    () => npcs.find((n) => n.name === npcName && n.areaCode === areaCode),
    [npcs, npcName, areaCode]
  );
  const currentGroup = React.useMemo(
    () => groupsInArea.find((g) => g.npcName === npcName),
    [groupsInArea, npcName]
  );

  // 过滤匹配 lineups + 候选下一只
  const matched = React.useMemo(() => {
    const all = currentGroup?.lineupList || [];
    const sel = new Set(selected);
    const filtered = all.filter((l) =>
      Array.from(sel).every((s) => (l.playerList || []).some((p) => p.name === s))
    );
    // 统计候选下一只 (按出现次数降序)
    const counts = {};
    for (const l of filtered) {
      const seen = new Set();
      for (const p of l.playerList || []) {
        if (sel.has(p.name) || seen.has(p.name)) continue;
        seen.add(p.name);
        counts[p.name] = (counts[p.name] || 0) + 1;
      }
    }
    const monsters = Object.entries(counts)
      .map(([name, count]) => ({ name, count }))
      .sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));
    return { lineups: filtered, monsters };
  }, [currentGroup, selected]);

  // 决策树: 按 selected[0] 反查 monsterId
  const tree = React.useMemo(() => {
    if (!currentNpc || !selected[0]) return null;
    // 反查 monsterId: 在当前 group 任何 lineup 里找这个名字
    let mid = null;
    for (const l of currentGroup?.lineupList || []) {
      const p = (l.playerList || []).find((x) => x.name === selected[0]);
      if (p?.monsterId) { mid = p.monsterId; break; }
    }
    if (mid == null) return null;
    return trees[String(currentNpc.id)]?.[String(mid)] || null;
  }, [currentNpc, currentGroup, selected, trees]);

  const remainingFocus = selected.slice(1);

  // 锁定查看(单/多)
  const lockedLineups = React.useMemo(() => {
    if (!lockedView) return [];
    const all = currentGroup?.lineupList || [];
    return all.filter((l) => lockedView.includes(l.id) || lockedView.includes(l.i));
  }, [lockedView, currentGroup]);

  if (!areas.length) {
    return (
      <div className="card card-pad">
        <window.Empty title="数据加载中…" hint="如果一直显示,确认 /simple_match.json 可访问"/>
      </div>
    );
  }

  return (
    <div>
      <div className="page-header">
        <div>
          <div className="breadcrumb">
            <span>日常</span><span className="sep">/</span><span>对战助手</span>
            {areaCode && <><span className="sep">/</span><span>{areas.find((a)=>a.code===areaCode)?.name || areaCode}</span></>}
            {npcName && <><span className="sep">/</span><span>{npcName}</span></>}
          </div>
          <h1 className="page-title">对战助手</h1>
          <div className="page-subtitle">
            选天王 → 选对面首发 → 看决策树。后续选择会自动收窄分支。
          </div>
        </div>
      </div>

      <div style={{ display:'grid', gridTemplateColumns: '260px 1fr', gap: 16, alignItems: 'flex-start' }}>
        {/* 左侧: 区域 + 天王选择 */}
        <div className="card card-pad-sm" style={{ position:'sticky', top: 16 }}>
          <div className="muted" style={{ fontSize: 11, marginBottom: 6, padding: '0 4px' }}>区域</div>
          <div style={{ display:'flex', flexWrap:'wrap', gap: 4, marginBottom: 12 }}>
            {areas.map((a) => (
              <button key={a.code} onClick={() => setAreaCode(a.code)}
                      className={`btn xs ${areaCode === a.code ? 'primary' : ''}`}>
                {a.name}
              </button>
            ))}
          </div>
          <div className="muted" style={{ fontSize: 11, marginBottom: 6, padding: '0 4px' }}>天王</div>
          {groupsInArea.length === 0 && (
            <div style={{ padding: 12, color: 'var(--text-3)', fontSize: 12 }}>该区域暂无数据</div>
          )}
          {groupsInArea.map((g) => (
            <div key={g.npcName}
                 className={`tree-item ${npcName === g.npcName ? 'active' : ''}`}
                 onClick={() => { setNpcName(g.npcName); setSelected([]); setLockedView(null); }}>
              <window.I.user size={13}/>
              {g.npcName}
              <span className="count">{(g.lineupList || []).length}</span>
            </div>
          ))}
        </div>

        {/* 右侧: 主区 */}
        <div style={{ display:'flex', flexDirection:'column', gap: 14 }}>
          {!npcName && <window.Empty title="选个天王开始" hint="左侧列表点一下"/>}

          {npcName && (
            <>
              {/* 已选 chips */}
              {selected.length > 0 && (
                <div className="card card-pad-sm" style={{ display:'flex', alignItems:'center', flexWrap:'wrap', gap: 6 }}>
                  <span className="muted" style={{ fontSize: 12, marginRight: 4 }}>已选</span>
                  {selected.map((name, i) => (
                    <button key={name}
                            onClick={() => setSelected(selected.filter((x) => x !== name))}
                            style={{
                              display: 'inline-flex', alignItems: 'center', gap: 6,
                              padding: '4px 10px',
                              border: '1px solid var(--border)',
                              borderRadius: 'var(--r-sm)',
                              background: i === 0 ? 'var(--primary-50)' : 'var(--surface)',
                              fontSize: 12,
                            }}>
                      <PetIcon name={name} size={20}/>
                      <span style={{ fontWeight: 500 }}>{name}</span>
                      {i === 0 && <span className="mono" style={{ fontSize: 10, color: 'var(--text-3)' }}>开盘</span>}
                      <window.I.x size={11} style={{ color: 'var(--danger)' }}/>
                    </button>
                  ))}
                  <button className="btn xs ghost" style={{ marginLeft: 'auto' }}
                          onClick={() => { setSelected([]); setLockedView(null); }}>
                    清空
                  </button>
                </div>
              )}

              {/* 决策树 */}
              {tree && hasTreeContent(tree) && (
                <DecisionTreePanel node={tree} depth={0} remainingFocus={remainingFocus}
                                   onShowLines={(ids) => setLockedView(ids)}/>
              )}
              {selected.length > 0 && !tree && (
                <div className="card card-pad-sm">
                  <window.I.info size={14} style={{ verticalAlign: 'middle', marginRight: 6 }}/>
                  暂无该首发的决策树,可直接在右下方"匹配的队伍"挑一条参考。
                </div>
              )}

              {/* 候选下一只 / 锁定提示 */}
              <div>
                <div className="hstack" style={{ marginBottom: 8 }}>
                  <div className="card-title">{selected.length === 0 ? '对方可能首发' : '下一只可能'}</div>
                  <span className="muted" style={{ fontSize: 12 }}>剩余 {matched.lineups.length} 套队伍</span>
                </div>

                {matched.monsters.length === 0 && matched.lineups.length === 0 && (
                  <window.Empty title="没有匹配的队伍" hint="试着取消一两只选择"/>
                )}

                {matched.monsters.length === 0 && matched.lineups.length === 1 && (
                  // 锁定到唯一队伍
                  <LineupDetail lineup={matched.lineups[0]}/>
                )}

                {matched.monsters.length > 0 && (
                  <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(180px, 1fr))', gap: 8 }}>
                    {matched.monsters.map((m) => (
                      <button key={m.name}
                              onClick={() => setSelected([...selected, m.name])}
                              className="card"
                              style={{
                                display:'flex', alignItems:'center', gap: 8,
                                padding: '8px 10px',
                                background: 'var(--surface)',
                                cursor:'pointer',
                                textAlign:'left',
                              }}>
                        <PetIcon name={m.name} size={36}/>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontWeight: 500, fontSize: 13, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{m.name}</div>
                          <div className="mono" style={{ fontSize: 11, color: 'var(--text-3)' }}>×{m.count}</div>
                        </div>
                      </button>
                    ))}
                  </div>
                )}

                {matched.lineups.length > 1 && (
                  <button onClick={() => setLockedView(matched.lineups.map((l) => l.id))}
                          className="btn" style={{ marginTop: 12, width: '100%' }}>
                    查看全部 {matched.lineups.length} 套匹配阵容 →
                  </button>
                )}
              </div>

              {/* 锁定队伍展开列表 */}
              {lockedView && lockedLineups.length > 0 && (
                <div className="card">
                  <div className="card-header">
                    <div className="card-title">锁定 {lockedLineups.length} 套队伍</div>
                    <button className="btn ghost xs" onClick={() => setLockedView(null)}>关闭</button>
                  </div>
                  <div style={{ padding: 12, display:'flex', flexDirection:'column', gap: 12 }}>
                    {lockedLineups.map((l) => (
                      <LineupDetail key={l.id} lineup={l}/>
                    ))}
                  </div>
                </div>
              )}
            </>
          )}
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────────
// 决策树渲染 (跟 iOS DecisionTreeView 同算法)

function hasTreeContent(node) {
  if (!node) return false;
  if (node.label) return true;
  if (node.operate) return true;
  if (node.attention) return true;
  if (node.children?.length) return true;
  if (node.lineList?.length) return true;
  return false;
}

function focusInChildren(kids, remainingFocus) {
  if (!remainingFocus?.length) return { focus: null, hit: null, rest: remainingFocus, otherCount: 0 };
  for (let i = 0; i < remainingFocus.length; i++) {
    const name = remainingFocus[i];
    const idx = kids.findIndex((k) => (k.label || '').includes(name));
    if (idx >= 0) {
      const rest = [...remainingFocus.slice(0, i), ...remainingFocus.slice(i + 1)];
      return { focus: kids[idx], hit: name, rest, otherCount: kids.length - 1 };
    }
  }
  return { focus: null, hit: null, rest: remainingFocus, otherCount: 0 };
}

function DecisionTreePanel({ node, depth, remainingFocus, onShowLines, focusedBy }) {
  const isRoot = depth === 0;
  const isFocused = !!focusedBy;
  const border = isFocused ? '2px solid var(--indigo)' : (isRoot ? '1px solid var(--border)' : '1px dashed var(--border-strong)');

  let focusedKid = null, hitName = null, restFocus = remainingFocus, otherCount = 0;
  if (node.children?.length) {
    ({ focus: focusedKid, hit: hitName, rest: restFocus, otherCount } = focusInChildren(node.children, remainingFocus));
  }

  return (
    <div>
      {focusedBy && (
        <div style={{ display:'inline-flex', alignItems:'center', gap: 6, marginBottom: 4 }}>
          <span style={{ fontSize: 11, color: 'var(--text-3)' }}>→ 对应你选的</span>
          <span style={{
            display:'inline-block', padding: '1px 6px',
            background: 'var(--indigo)', color:'white',
            borderRadius: 'var(--r-sm)',
            fontSize: 11, fontWeight: 600,
          }}>{focusedBy}</span>
        </div>
      )}
      <div style={{
        padding: isRoot ? 14 : 10,
        border,
        background: isRoot ? 'var(--surface)' : 'var(--surface-2)',
      }}>
        <div className="hstack" style={{ alignItems: 'flex-start', gap: 8 }}>
          <span style={{ fontSize: 14, color: isRoot ? 'var(--warning)' : 'var(--text-3)' }}>{isRoot ? '★' : '◎'}</span>
          <div style={{ flex: 1, fontSize: isRoot ? 15 : 13, lineHeight: 1.5 }}>
            <span style={{ fontWeight: 600 }}>{node.label || ''}</span>
            {node.operate && <span style={{ color: 'var(--danger)' }}> → {node.operate}</span>}
          </div>
          {node.lineList?.length > 0 && (
            <button className="btn xs"
                    onClick={() => onShowLines(node.lineList)}
                    style={{ whiteSpace:'nowrap' }}>
              查看队伍 <span style={{
                marginLeft: 4, padding: '0 5px',
                background: 'var(--warning)', color: 'var(--text)',
                borderRadius: 'var(--r-sm)', fontFamily:'var(--font-mono)', fontSize: 11,
              }}>{node.lineList.length}</span>
            </button>
          )}
        </div>
        {node.attention && (
          <div style={{
            marginTop: 8, padding: '6px 10px',
            background: 'var(--warning)', color: 'var(--text)',
            borderRadius: 'var(--r-sm)',
            fontSize: 12, fontWeight: 500,
          }}>⚠ {node.attention}</div>
        )}
        {node.remark && (
          <div style={{ marginTop: 6, fontSize: 11, color: 'var(--text-3)' }}>{node.remark}</div>
        )}
        {node.children?.length > 0 && (
          <div style={{ marginTop: 10, display:'flex', flexDirection:'column', gap: 8, paddingLeft: 12 }}>
            {focusedKid ? (
              <>
                <DecisionTreePanel
                  node={focusedKid}
                  depth={depth + 1}
                  remainingFocus={restFocus}
                  onShowLines={onShowLines}
                  focusedBy={hitName}
                />
                {otherCount > 0 && (
                  <div style={{ fontSize: 11, color: 'var(--text-3)' }}>已隐藏其它 {otherCount} 条不匹配的分支</div>
                )}
              </>
            ) : (
              node.children.map((c, i) => (
                <DecisionTreePanel
                  key={i}
                  node={c}
                  depth={depth + 1}
                  remainingFocus={remainingFocus}
                  onShowLines={onShowLines}
                />
              ))
            )}
          </div>
        )}
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────────
// 单条 lineup 详情
function LineupDetail({ lineup }) {
  const meta = [
    lineup.speed && ['速度', lineup.speed],
    lineup.drug && ['药水', lineup.drug],
    lineup.weather && ['天气', lineup.weather],
    lineup.ding && ['', '定'],
    lineup.lock && ['', '锁'],
    lineup.chu && ['', '初'],
  ].filter(Boolean);

  return (
    <div className="card">
      <div className="card-header" style={{ padding: '10px 14px' }}>
        <div className="card-title">{lineup.idx || `队伍 ${lineup.i || lineup.id}`}</div>
        <div className="hstack" style={{ gap: 4, flexWrap:'wrap' }}>
          {meta.map(([k, v], i) => (
            <span key={i} className="mono" style={{
              padding: '2px 6px',
              background: 'var(--surface-2)',
              border: '1px solid var(--border)',
              borderRadius: 'var(--r-sm)',
              fontSize: 11,
            }}>{k && <span style={{ color: 'var(--text-3)', marginRight: 4 }}>{k}</span>}{v}</span>
          ))}
        </div>
      </div>
      <div style={{ padding: 12, display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(160px, 1fr))', gap: 10 }}>
        {(lineup.playerList || []).map((p, i) => (
          <PlayerCard key={i} player={p}/>
        ))}
      </div>
    </div>
  );
}

function PlayerCard({ player }) {
  const moves = [player.skillA, player.skillB, player.skillC, player.skillD].filter(Boolean);
  return (
    <div style={{
      padding: 10,
      border: '1px solid var(--border)',
      borderRadius: 'var(--r-sm)',
      background: 'var(--surface)',
    }}>
      <div style={{ display:'flex', alignItems:'center', gap: 8, marginBottom: 6 }}>
        <PetIcon name={player.name} size={36}/>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 600, fontSize: 13 }}>{player.name}</div>
          <div className="mono" style={{ fontSize: 10, color: 'var(--text-3)' }}>
            {[player.firstAttribute, player.secondAttribute].filter(Boolean).join(' / ')}
          </div>
        </div>
      </div>
      {(player.equip || player.character) && (
        <div style={{ fontSize: 11, color: 'var(--text-2)', marginBottom: 4 }}>
          {[player.equip, player.character].filter(Boolean).join(' · ')}
        </div>
      )}
      {moves.length > 0 && (
        <div className="mono" style={{ fontSize: 11, color: 'var(--text-3)' }}>
          {moves.join(' / ')}
        </div>
      )}
    </div>
  );
}

function PetIcon({ name, size = 36 }) {
  const [failed, setFailed] = React.useState(false);
  const url = `/img/pet/${encodeURIComponent(name)}.png`;
  return (
    <div style={{
      width: size, height: size,
      background: 'var(--surface-2)',
      border: '1px solid var(--border)',
      borderRadius: 'var(--r-sm)',
      display: 'grid', placeItems: 'center', overflow: 'hidden',
    }}>
      {failed ? (
        <span style={{ fontSize: Math.max(10, size / 4), color: 'var(--text-3)' }}>?</span>
      ) : (
        <img src={url} alt={name} style={{ width: '100%', height: '100%', objectFit: 'contain' }}
             onError={() => setFailed(true)}/>
      )}
    </div>
  );
}

Object.assign(window, { MatcherPage });
