// ============================================================================
// TERRITORY-PICKERS — three interchangeable pickers + a unified container.
//
// <TerritoryPicker selection={sel} onChange={setSel} mode="auto" />
//   Renders chip / tree / map based on `mode` (defaults to user's preference
//   stored in localStorage 'astro_territory_picker_mode').
//
// <TerritoryChips selection onChange />
//   Compact chip / search / quick-bloc affordances.
//
// <TerritoryTree selection onChange />
//   World → Region → Subregion → Country expandable tree.
//
// <TerritoryMap selection onChange />
//   Lightweight tile-based world heatmap (pure SVG, no external libs).
//   Each ISO country is a rect on a flow grid, colored by selection state.
//   Hover to see name + flag; click to toggle.
//
// <TerritorySummary selection /> — read-only label/count, used inline.
//
// EXPORT: window.TerritoryPicker, window.TerritoryChips, window.TerritoryTree,
//         window.TerritoryMap, window.TerritorySummary
// ============================================================================
(function () {
  const { useState, useMemo, useEffect, useRef } = React;
  const TE = () => window.TerritoryEngine;

  // ── Selection helpers.
  function withCode(sel, code) {
    const codes = (sel.codes || []).slice();
    if (!codes.includes(code)) codes.push(code);
    return { ...sel, mode: sel.mode === 'world' ? 'list' : (sel.mode || 'list'), codes };
  }
  function withoutCode(sel, code) {
    return { ...sel, codes: (sel.codes || []).filter(c => c !== code) };
  }
  function toggleExclude(sel, code) {
    const ex = (sel.excludes || []).slice();
    const i = ex.indexOf(code);
    if (i >= 0) ex.splice(i, 1); else ex.push(code);
    return { ...sel, excludes: ex };
  }

  // ── TerritorySummary — read-only label.
  function TerritorySummary({ selection, max = 4, style }) {
    const eng = TE(); if (!eng) return null;
    const { isos, label } = eng.resolveSelection(selection);
    const flags = Array.from(isos).slice(0, max).map(eng.flagOf).join(' ');
    return (
      <span className="ff-mono" style={Object.assign({ fontSize: 11, color: 'var(--ink)' }, style || {})}>
        <span style={{ marginRight: 6 }}>{flags}</span>
        <span>{label}</span>
        <span style={{ color: 'var(--ink-3)', marginLeft: 6 }}>· {isos.size} ISO</span>
      </span>
    );
  }

  // ── Chip picker.
  function TerritoryChips({ selection, onChange, hideQuick }) {
    const eng = TE(); if (!eng) return null;
    const [search, setSearch] = useState('');
    const [showAll, setShowAll] = useState(false);
    const sel = selection || { mode: 'list', codes: [] };
    const codes = sel.codes || [];

    const blocs = eng.listBlocs();
    const tisRegions = eng.listTis().filter(n => n.kind === 'region' || n.kind === 'subreg');

    // Search results — countries.
    const REF = window.REF;
    const allCountries = (REF && REF.ready && REF.territories) ? REF.territories : null;
    const searchHits = useMemo(() => {
      if (!search) return [];
      const s = search.toLowerCase();
      if (allCountries) {
        return allCountries.filter(t =>
          (t.iso_alpha_2 && t.iso_alpha_2.toLowerCase().startsWith(s)) ||
          (t.common_name && t.common_name.toLowerCase().includes(s)) ||
          (t.iso_alpha_3 && t.iso_alpha_3.toLowerCase().startsWith(s))
        ).slice(0, 12);
      }
      return eng.allIso().filter(iso => iso.toLowerCase().startsWith(s)).slice(0, 12).map(iso => ({ iso_alpha_2: iso, common_name: iso, emoji_flag: eng.flagOf(iso) }));
    }, [search, allCountries]);

    return (
      <div>
        {/* Mode chips */}
        <div style={{ display: 'flex', gap: 6, marginBottom: 10, flexWrap: 'wrap' }}>
          {[
            ['world',   'World'],
            ['list',    'Specific list'],
            ['exclude', 'World except'],
          ].map(([k, l]) => (
            <button key={k} onClick={() => onChange({ ...sel, mode: k, codes: k === 'world' ? [] : codes })}
              className="ff-mono upper"
              style={{
                padding: '4px 10px', fontSize: 10, letterSpacing: '.1em',
                background: sel.mode === k ? 'var(--ink)' : 'transparent',
                color: sel.mode === k ? 'var(--bg)' : 'var(--ink)',
                border: '1px solid ' + (sel.mode === k ? 'var(--ink)' : 'var(--rule)'),
                cursor: 'pointer',
              }}>{l}</button>
          ))}
        </div>

        {/* Selected codes */}
        {sel.mode !== 'world' && (
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10, minHeight: 28, padding: 6, border: '1px solid var(--rule)', background: 'var(--bg-2)' }}>
            {codes.length === 0 && <span className="ff-mono" style={{ fontSize: 11, color: 'var(--ink-3)' }}>add territories below…</span>}
            {codes.map(c => (
              <span key={c} className="ff-mono" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '3px 8px', background: 'var(--bg)', border: '1px solid var(--ink)', fontSize: 11 }}>
                <span>{eng.flagOf(c) || ''}</span>
                <span>{eng.labelOf(c)}</span>
                <button onClick={() => onChange(withoutCode(sel, c))} style={{ marginLeft: 2, padding: 0, color: 'var(--ink-3)', fontSize: 12 }}>×</button>
              </span>
            ))}
          </div>
        )}

        {/* Excludes */}
        {(sel.excludes && sel.excludes.length > 0) && (
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10, padding: 6, border: '1px dashed var(--danger)', background: 'transparent' }}>
            <span className="ff-mono upper" style={{ fontSize: 9, color: 'var(--danger)', alignSelf: 'center' }}>EX:</span>
            {sel.excludes.map(c => (
              <span key={c} className="ff-mono" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '3px 8px', background: 'var(--bg)', border: '1px solid var(--danger)', color: 'var(--danger)', fontSize: 11 }}>
                <span>{eng.flagOf(c) || ''}</span>
                <span>{eng.labelOf(c)}</span>
                <button onClick={() => onChange(toggleExclude(sel, c))} style={{ marginLeft: 2, padding: 0, color: 'var(--danger)', fontSize: 12 }}>×</button>
              </span>
            ))}
          </div>
        )}

        {/* Quick blocs */}
        {!hideQuick && sel.mode !== 'world' && (
          <div>
            <div className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em', marginBottom: 6 }}>QUICK BLOCS</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 12 }}>
              {blocs.slice(0, showAll ? 999 : 9).map(b => {
                const active = codes.includes(b.code);
                return (
                  <button key={b.code} onClick={() => onChange(active ? withoutCode(sel, b.code) : withCode(sel, b.code))}
                    className="ff-mono"
                    style={{
                      padding: '3px 8px', fontSize: 10, letterSpacing: '.04em',
                      background: active ? 'var(--ink)' : 'transparent',
                      color: active ? 'var(--bg)' : 'var(--ink-2)',
                      border: '1px solid ' + (active ? 'var(--ink)' : 'var(--rule)'),
                      cursor: 'pointer',
                    }}>
                    {b.label} <span style={{ opacity: 0.55 }}>·{b.leaves.length}</span>
                  </button>
                );
              })}
              {blocs.length > 9 && (
                <button onClick={() => setShowAll(!showAll)} className="ff-mono upper" style={{ fontSize: 9, padding: '3px 8px', color: 'var(--ink-3)', background: 'transparent', border: '1px dashed var(--rule)' }}>
                  {showAll ? '− less' : `+${blocs.length - 9} more`}
                </button>
              )}
            </div>
          </div>
        )}

        {/* TIS regions */}
        {sel.mode !== 'world' && (
          <div>
            <div className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em', marginBottom: 6 }}>TIS REGIONS</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 12 }}>
              {tisRegions.map(r => {
                const active = codes.includes(r.code);
                return (
                  <button key={r.code} onClick={() => onChange(active ? withoutCode(sel, r.code) : withCode(sel, r.code))}
                    className="ff-mono"
                    style={{
                      padding: '3px 8px', fontSize: 10,
                      background: active ? 'var(--ink)' : 'transparent',
                      color: active ? 'var(--bg)' : 'var(--ink-2)',
                      border: '1px solid ' + (active ? 'var(--ink)' : 'var(--rule)'),
                      cursor: 'pointer',
                    }}>
                    <span style={{ opacity: 0.55, marginRight: 4 }}>{r.code}</span>
                    {r.label}
                  </button>
                );
              })}
            </div>
          </div>
        )}

        {/* Country search */}
        {sel.mode !== 'world' && (
          <div>
            <div className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em', marginBottom: 6 }}>SEARCH COUNTRIES</div>
            <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Type country, ISO, or name…"
              style={{ width: '100%', padding: '6px 10px', fontSize: 12, fontFamily: 'inherit', background: 'var(--bg)', border: '1px solid var(--rule)', boxSizing: 'border-box' }} />
            {search && (
              <div style={{ marginTop: 6, display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                {searchHits.map(t => {
                  const c = t.iso_alpha_2;
                  const active = codes.includes(c);
                  return (
                    <button key={c} onClick={() => onChange(active ? withoutCode(sel, c) : withCode(sel, c))}
                      className="ff-mono"
                      style={{
                        padding: '3px 8px', fontSize: 11,
                        background: active ? 'var(--ink)' : 'var(--bg)',
                        color: active ? 'var(--bg)' : 'var(--ink)',
                        border: '1px solid ' + (active ? 'var(--ink)' : 'var(--rule)'),
                        cursor: 'pointer',
                      }}>
                      {(t.emoji_flag || eng.flagOf(c) || '')} {c} {t.common_name && t.common_name !== c ? '· ' + t.common_name : ''}
                    </button>
                  );
                })}
                {searchHits.length === 0 && <span className="ff-mono" style={{ fontSize: 11, color: 'var(--ink-3)' }}>no match</span>}
              </div>
            )}
          </div>
        )}

        {/* World mode: optional excludes */}
        {sel.mode === 'world' && !hideQuick && (
          <div style={{ marginTop: 8 }}>
            <div className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em', marginBottom: 6 }}>EXCLUDE</div>
            <input placeholder="ISO codes to exclude (e.g. RU, IR, KP)…" onKeyDown={e => {
              if (e.key === 'Enter' && e.target.value.trim()) {
                const code = e.target.value.trim().toUpperCase();
                onChange({ ...sel, excludes: [...(sel.excludes || []), code] });
                e.target.value = '';
              }
            }} style={{ width: '100%', padding: '6px 10px', fontSize: 12, fontFamily: 'inherit', background: 'var(--bg)', border: '1px solid var(--rule)', boxSizing: 'border-box' }} />
          </div>
        )}
      </div>
    );
  }

  // ── Tree picker.
  function TerritoryTree({ selection, onChange }) {
    const eng = TE(); if (!eng) return null;
    const [open, setOpen] = useState({ '2136': true, '2100': true });
    const sel = selection || { mode: 'list', codes: [] };
    const isos = eng.resolveSelection(sel).isos;

    function toggle(code) {
      const codes = (sel.codes || []).slice();
      const i = codes.indexOf(code);
      if (i >= 0) codes.splice(i, 1); else codes.push(code);
      onChange({ ...sel, mode: sel.mode === 'world' ? 'list' : (sel.mode || 'list'), codes });
    }

    function Node({ code, depth }) {
      const TIS = eng.TIS;
      const node = TIS[code];
      if (!node) return null;
      const isOpen = !!open[code];
      const childCodes = node.children || [];
      const leafIsos = node.leaves || [];
      const isPicked = (sel.codes || []).includes(code);
      const childCount = leafIsos.length || childCodes.reduce((s, c) => s + (eng.expand(c).size), 0);
      const includedHere = leafIsos.filter(iso => isos.has(iso)).length || (childCodes.reduce((s, c) => s + Array.from(eng.expand(c)).filter(iso => isos.has(iso)).length, 0));
      return (
        <div style={{ marginLeft: depth * 16 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '4px 0' }}>
            {(childCodes.length || leafIsos.length) ? (
              <button onClick={() => setOpen(o => ({ ...o, [code]: !isOpen }))} style={{ width: 16, padding: 0, color: 'var(--ink-3)' }}>{isOpen ? '▾' : '▸'}</button>
            ) : <span style={{ width: 16 }} />}
            <button onClick={() => toggle(code)} className="ff-mono" style={{
              padding: '2px 6px', fontSize: 11,
              background: isPicked ? 'var(--ink)' : 'transparent',
              color: isPicked ? 'var(--bg)' : 'var(--ink)',
              border: '1px solid ' + (isPicked ? 'var(--ink)' : 'var(--rule)'),
              cursor: 'pointer',
            }}>
              <span style={{ opacity: 0.55, marginRight: 4 }}>{node.code}</span>
              {node.label}
            </button>
            <span className="ff-mono" style={{ fontSize: 10, color: 'var(--ink-3)' }}>· {includedHere}/{childCount}</span>
          </div>
          {isOpen && childCodes.map(c => <Node key={c} code={c} depth={depth + 1} />)}
          {isOpen && leafIsos.length > 0 && (
            <div style={{ marginLeft: (depth + 1) * 16, display: 'flex', flexWrap: 'wrap', gap: 4, padding: '4px 0' }}>
              {leafIsos.map(iso => {
                const picked = isos.has(iso);
                const explicit = (sel.codes || []).includes(iso);
                return (
                  <button key={iso} onClick={() => toggle(iso)} className="ff-mono"
                    style={{
                      padding: '2px 6px', fontSize: 10,
                      background: explicit ? 'var(--ink)' : (picked ? 'var(--bg-2)' : 'transparent'),
                      color: explicit ? 'var(--bg)' : 'var(--ink-2)',
                      border: '1px solid ' + (explicit ? 'var(--ink)' : 'var(--rule)'),
                      cursor: 'pointer',
                    }}>
                    {eng.flagOf(iso) || ''} {iso}
                  </button>
                );
              })}
            </div>
          )}
        </div>
      );
    }

    return (
      <div style={{ border: '1px solid var(--rule)', padding: 12, maxHeight: 480, overflow: 'auto' }}>
        <Node code="2136" depth={0} />
      </div>
    );
  }

  // ── Map picker — lightweight tile heatmap.
  // Layout: countries arranged in a 24×12 grid by approximate longitude/latitude.
  // Not geographically accurate, but readable and zero-dep.
  const MAP_GRID = [
    // y=0 (top, north)
    'IS','GL','','','','','','','','','','','','','','','','','','','','RU','RU','RU',
    'NO','SE','FI','EE','LV','LT','BY','RU','RU','RU','MN','','','','','','','','','','','','','',
    'IE','GB','DK','NL','DE','PL','UA','MD','GE','AM','AZ','TM','UZ','KZ','KG','TJ','CN','KP','KR','JP','','','','',
    'PT','ES','FR','BE','LU','CH','AT','CZ','SK','HU','RO','BG','TR','IR','AF','PK','NP','BT','BD','MM','TW','HK','','',
    '','','MA','IT','SM','HR','SI','RS','BA','ME','AL','MK','GR','CY','SY','LB','IL','JO','IQ','SA','QA','AE','OM','YE',
    '','EH','DZ','TN','LY','EG','SD','ER','DJ','SO','ET','UG','KE','TZ','RW','BI','','IN','LK','MV','TH','VN','PH','',
    '','','MR','ML','NE','TD','CF','SS','','','','','','','','','','LA','KH','MY','SG','BN','ID','',
    '','','SN','GM','GN','BF','BJ','NG','CM','GA','CG','CD','AO','ZM','MW','MZ','ZW','BW','NA','MG','','','PG','',
    '','','','','GH','TG','','','','','','','','','','','','ZA','LS','SZ','','','','',
    '','','US','US','US','US','CA','CA','CA','','','','','','','','','','','AU','NZ','','','',
    'CU','BS','MX','GT','HN','SV','NI','CR','PA','CO','VE','GY','SR','BR','BR','BR','BR','','','','NC','FJ','','',
    '','','','EC','PE','BO','PY','CL','AR','UY','','','','','','','','','','','','','','',
  ];

  function TerritoryMap({ selection, onChange }) {
    const eng = TE(); if (!eng) return null;
    const sel = selection || { mode: 'list', codes: [] };
    const isos = eng.resolveSelection(sel).isos;
    const explicit = new Set(sel.codes || []);
    const excludes = new Set(sel.excludes || []);
    const [hover, setHover] = useState(null);

    const cols = 24;
    const rows = MAP_GRID.length;
    const cellW = 26, cellH = 22;

    function toggle(iso) {
      if (!iso) return;
      const has = (sel.codes || []).includes(iso);
      if (sel.mode === 'world' || sel.mode === 'exclude') {
        // toggle exclude
        const ex = (sel.excludes || []).slice();
        const i = ex.indexOf(iso);
        if (i >= 0) ex.splice(i, 1); else ex.push(iso);
        onChange({ ...sel, excludes: ex });
      } else {
        const codes = (sel.codes || []).slice();
        if (has) codes.splice(codes.indexOf(iso), 1); else codes.push(iso);
        onChange({ ...sel, codes });
      }
    }

    return (
      <div style={{ position: 'relative', border: '1px solid var(--rule)', padding: 14, background: 'var(--bg-2)' }}>
        <svg width={cols * cellW} height={rows * cellH} style={{ display: 'block', maxWidth: '100%' }}>
          {MAP_GRID.map((row, y) => {
            const cells = row.split(',');
            return cells.map((iso, x) => {
              if (!iso) return null;
              const inSel = isos.has(iso);
              const isExplicit = explicit.has(iso);
              const isExcluded = excludes.has(iso);
              const fill = isExcluded ? 'var(--danger)' : (isExplicit ? 'var(--ink)' : (inSel ? 'var(--ink-2)' : 'var(--bg)'));
              const fg = (isExplicit || isExcluded || inSel) ? 'var(--bg)' : 'var(--ink-3)';
              return (
                <g key={`${x}-${y}-${iso}`} transform={`translate(${x * cellW}, ${y * cellH})`}
                   onMouseEnter={() => setHover(iso)} onMouseLeave={() => setHover(null)}
                   onClick={() => toggle(iso)} style={{ cursor: 'pointer' }}>
                  <rect x={1} y={1} width={cellW - 2} height={cellH - 2} fill={fill} stroke="var(--rule)" strokeWidth={0.5} />
                  <text x={cellW / 2} y={cellH / 2 + 4} textAnchor="middle" fontSize={9} fontFamily="IBM Plex Mono, monospace" fill={fg}>{iso}</text>
                </g>
              );
            });
          })}
        </svg>
        {hover && (
          <div style={{ position: 'absolute', bottom: 12, right: 14, padding: '6px 10px', background: 'var(--ink)', color: 'var(--bg)', fontSize: 11, fontFamily: 'IBM Plex Mono, monospace' }}>
            {eng.flagOf(hover)} {hover} · {eng.labelOf(hover)}
          </div>
        )}
        <div style={{ marginTop: 10, display: 'flex', gap: 16, fontSize: 10, fontFamily: 'IBM Plex Mono, monospace', color: 'var(--ink-3)' }}>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}><span style={{ width: 12, height: 12, background: 'var(--ink)', display: 'inline-block' }}></span> picked explicit</span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}><span style={{ width: 12, height: 12, background: 'var(--ink-2)', display: 'inline-block' }}></span> via region/bloc</span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}><span style={{ width: 12, height: 12, background: 'var(--danger)', display: 'inline-block' }}></span> excluded</span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}><span style={{ width: 12, height: 12, background: 'var(--bg)', border: '1px solid var(--rule)', display: 'inline-block' }}></span> not selected</span>
        </div>
      </div>
    );
  }

  // ── Unified picker container — toggle between modes.
  function TerritoryPicker({ selection, onChange, mode, allowMode = ['chips', 'tree', 'map'] }) {
    const stored = (() => { try { return localStorage.getItem('astro_territory_picker_mode') || 'chips'; } catch { return 'chips'; } })();
    const [m, setM] = useState(mode || stored);
    useEffect(() => { try { localStorage.setItem('astro_territory_picker_mode', m); } catch {} }, [m]);

    return (
      <div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
          <TerritorySummary selection={selection} />
          <div style={{ display: 'flex', gap: 4 }}>
            {allowMode.map(k => (
              <button key={k} onClick={() => setM(k)} className="ff-mono upper"
                style={{
                  padding: '3px 8px', fontSize: 9, letterSpacing: '.12em',
                  background: m === k ? 'var(--ink)' : 'transparent',
                  color: m === k ? 'var(--bg)' : 'var(--ink-3)',
                  border: '1px solid ' + (m === k ? 'var(--ink)' : 'var(--rule)'),
                  cursor: 'pointer',
                }}>{k}</button>
            ))}
          </div>
        </div>
        {m === 'chips' && <TerritoryChips selection={selection} onChange={onChange} />}
        {m === 'tree' && <TerritoryTree selection={selection} onChange={onChange} />}
        {m === 'map' && <TerritoryMap selection={selection} onChange={onChange} />}
      </div>
    );
  }

  window.TerritoryPicker = TerritoryPicker;
  window.TerritoryChips = TerritoryChips;
  window.TerritoryTree = TerritoryTree;
  window.TerritoryMap = TerritoryMap;
  window.TerritorySummary = TerritorySummary;
})();
