/* global React, SCHOOLS, COLLEGES, Eyebrow, Card, Pill, Button, Input,
   SectionHeader, Segmented, setSchoolGrade, setCollegeGrade */

/* Skolor & Colleges — the planning layer from Family/Football/.
 *
 * Two lists, one instrument. The three axes (academics / football / hockey)
 * are graded by research; `mine` is Pelle's own grade and it feeds the Fit
 * score, weighted by whichever lens is selected.
 *
 * Admin-only: mounted by TopBar for admins. It carries fee data, the family's
 * plan and Pelle's private grading, and the boys do not need it in front of
 * them every time they open the app.
 */
const { useState, useMemo } = React;

const GRADE_VALUE = {
  'A+': 13, 'A': 12, 'A-': 11,
  'B+': 10, 'B': 9, 'B-': 8,
  'C+': 7, 'C': 6, 'C-': 5, 'D': 4,
};
const GRADE_CYCLE = ['', 'A+', 'A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'D'];

/* Lenses. `mine` carries real weight in every one of them — it is a judgement
 * formed by a parent who has read the notes, not a tiebreak. */
const LENSES = [
  { id: 'balanced',  label: 'Balanserad', w: { aca: 1, fb: 1, hk: 1,   mine: 1 } },
  { id: 'academic',  label: 'Akademiskt', w: { aca: 3, fb: 1, hk: 0.5, mine: 1 } },
  { id: 'football',  label: 'Football',   w: { aca: 1, fb: 3, hk: 0.5, mine: 1 } },
  { id: 'hockey',    label: 'Hockey',     w: { aca: 1, fb: 0.5, hk: 3, mine: 1 } },
  { id: 'axel',      label: 'Axel',       w: { aca: 2, fb: 2, hk: 0,   mine: 1 } },
  { id: 'mine',      label: 'Min känsla', w: { aca: 0, fb: 0, hk: 0,   mine: 1 } },
];

function gradeColor(g) {
  const v = GRADE_VALUE[g];
  if (v == null) return 'var(--fg-muted)';
  if (v >= 12) return 'var(--signal)';
  if (v >= 10) return 'var(--ink-600)';
  if (v >= 8) return 'var(--ink-500)';
  return 'var(--ink-400)';
}

/* Fit: weighted mean over the axes that are actually present. A missing axis
 * is substituted with the row's own mean rather than zero, so an ungraded
 * hockey column does not silently punish a school nobody has rated yet. */
function fitScore(row, lens) {
  const w = lens.w;
  const axes = ['aca', 'fb', 'hk', 'mine'];
  const present = axes
    .map(a => ({ a, v: GRADE_VALUE[row[a]] }))
    .filter(x => x.v != null);
  if (!present.length) return null;
  const mean = present.reduce((s, x) => s + x.v, 0) / present.length;

  let num = 0, den = 0;
  for (const a of axes) {
    const weight = w[a] || 0;
    if (!weight) continue;
    const v = GRADE_VALUE[row[a]];
    num += (v == null ? mean : v) * weight;
    den += weight;
  }
  return den ? num / den : null;
}

/* Grade cell. Click cycles; a plain button, never a <select> — native selects
 * inside a scrollable table swallow wheel events and change the wrong row. */
function GradeCell({ value, onSet, editable }) {
  const label = value || '–';
  if (!editable) {
    return <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--text-sm)',
                          color: gradeColor(value), fontWeight: 'var(--weight-medium)' }}>{label}</span>;
  }
  return (
    <button
      onClick={(e) => {
        e.preventDefault();
        const i = GRADE_CYCLE.indexOf(value || '');
        onSet(GRADE_CYCLE[(i + 1) % GRADE_CYCLE.length] || null);
      }}
      title="Klicka för att ändra"
      style={{
        font: 'inherit', fontFamily: 'var(--font-mono)', fontSize: 'var(--text-sm)',
        fontWeight: 'var(--weight-medium)', color: gradeColor(value),
        background: value ? 'var(--ink-50)' : 'transparent',
        border: '1px solid ' + (value ? 'var(--ink-100)' : 'transparent'),
        borderRadius: 6, padding: '2px 8px', cursor: 'pointer', minWidth: 38,
      }}
    >{label}</button>
  );
}

/* Column model. `type` drives both the comparator and the default direction,
 * so a new column only has to be described, not special-cased. */
const COLS_SCHOOL = [
  { key: 'name', label: 'Namn',   type: 'text' },
  { key: 'loc',  label: 'Ort',    type: 'text' },
  { key: 'aca',  label: 'Aka',    type: 'grade', center: true },
  { key: 'fb',   label: 'FB',     type: 'grade', center: true },
  { key: 'hk',   label: 'HK',     type: 'grade', center: true },
  { key: 'mine', label: 'Min',    type: 'grade', center: true },
  { key: '_fit', label: 'Fit',    type: 'num',   center: true },
  { key: 'fee',    label: 'Avgift', type: 'num' },
  { key: 'region', label: 'Region', type: 'text' },
  { key: 'entry',  label: 'Intag',  type: 'text' },
];
const COLS_COLLEGE = [
  { key: 'name', label: 'Namn', type: 'text' },
  { key: 'loc',  label: 'Ort',  type: 'text' },
  { key: 'aca',  label: 'Aka',  type: 'grade', center: true },
  { key: 'fb',   label: 'FB',   type: 'grade', center: true },
  { key: 'hk',   label: 'HK',   type: 'grade', center: true },
  { key: 'mine', label: 'Min',  type: 'grade', center: true },
  { key: '_fit', label: 'Fit',  type: 'num',   center: true },
  { key: 'div',  label: 'Div',  type: 'text' },
  { key: 'conf', label: 'Konf', type: 'text' },
];

function sortValue(row, col) {
  const raw = row[col.key];
  if (col.type === 'grade') return GRADE_VALUE[raw] != null ? GRADE_VALUE[raw] : null;
  if (col.type === 'num')   return (raw === '' || raw == null) ? null : Number(raw);
  return (raw == null || raw === '') ? null : String(raw);
}

/* Blanks always sink to the bottom regardless of direction — an ungraded row
 * is not "the worst", it is unknown, and flipping the sort should not parade
 * unknowns at the top. */
function compareRows(a, b, col, dir) {
  const va = sortValue(a, col), vb = sortValue(b, col);
  if (va == null && vb == null) return 0;
  if (va == null) return 1;
  if (vb == null) return -1;
  const cmp = (col.type === 'text') ? va.localeCompare(vb, 'sv') : (va - vb);
  return dir === 'asc' ? cmp : -cmp;
}

function SortHeader({ col, sort, onSort }) {
  const active = sort.key === col.key;
  return (
    <th
      onClick={() => onSort(col)}
      title="Klicka för att sortera"
      style={{
        textAlign: col.center ? 'center' : 'left',
        padding: '10px 10px', fontSize: 'var(--text-2xs)',
        letterSpacing: 'var(--tracking-wider)', textTransform: 'uppercase',
        color: active ? 'var(--signal)' : 'var(--fg-muted)',
        fontWeight: 'var(--weight-medium)', whiteSpace: 'nowrap',
        cursor: 'pointer', userSelect: 'none',
      }}
    >
      {col.label}
      <span style={{ marginLeft: 4, opacity: active ? 1 : 0.25 }}>
        {active ? (sort.dir === 'asc' ? '\u25B2' : '\u25BC') : '\u25BE'}
      </span>
    </th>
  );
}

function SkolorScreen({ isAdmin, isMobile }) {
  const [tab, setTab] = useState('skolor');
  const [lensId, setLens] = useState('balanced');
  const [q, setQ] = useState('');
  const [region, setRegion] = useState('alla');
  // { key, dir }. Grades and numbers default to descending (best first);
  // text defaults to ascending. Clicking the active column flips it.
  const [sort, setSort] = useState({ key: '_fit', dir: 'desc' });
  const [bump, setBump] = useState(0);
  const lens = LENSES.find(l => l.id === lensId) || LENSES[0];

  const cols = tab === 'skolor' ? COLS_SCHOOL : COLS_COLLEGE;

  const rows = useMemo(() => {
    const src = (tab === 'skolor' ? (window.SCHOOLS || []) : (window.COLLEGES || [])).slice();
    const needle = q.trim().toLowerCase();
    const byRegion = (tab === 'skolor' && region !== 'alla')
      ? src.filter(r => r.region === region)
      : src;
    const filtered = needle
      ? byRegion.filter(r => (r.name + ' ' + (r.loc || '') + ' ' + (r.conf || '')).toLowerCase().includes(needle))
      : byRegion;
    const scored = filtered.map(r => ({ ...r, _fit: fitScore(r, lens) }));
    const col = cols.find(c => c.key === sort.key) || cols.find(c => c.key === '_fit');
    scored.sort((a, b) => compareRows(a, b, col, sort.dir));
    return scored;
  }, [tab, lensId, q, region, sort, bump]);

  const onSort = (col) => setSort(prev =>
    prev.key === col.key
      ? { key: col.key, dir: prev.dir === 'asc' ? 'desc' : 'asc' }
      // Text reads best A→Z; grades and numbers best-first.
      : { key: col.key, dir: col.type === 'text' ? 'asc' : 'desc' }
  );

  const setGrade = (row, val) => {
    row.mine = val;
    if (tab === 'skolor') window.setSchoolGrade && window.setSchoolGrade(row.id, val);
    else window.setCollegeGrade && window.setCollegeGrade(row.id, val);
    setBump(b => b + 1);
  };

  const graded = rows.filter(r => r.mine).length;

  return (
    <div style={{ padding: isMobile ? '16px 12px 80px' : '24px 16px 60px', maxWidth: 1280, margin: '0 auto' }}>
      <SectionHeader
        eyebrow="Planering"
        title={tab === 'skolor' ? 'Skolor' : 'Colleges'}
        action={
          <Segmented
            options={[{ value: 'skolor', label: 'Skolor' }, { value: 'colleges', label: 'Colleges' }]}
            value={tab}
            onChange={setTab}
          />
        }
      />

      <Card pad={isMobile ? 14 : 18} style={{ marginBottom: 16 }}>
        <Eyebrow>Lins</Eyebrow>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, margin: '8px 0 14px' }}>
          {LENSES.map(l => (
            <button key={l.id} onClick={() => setLens(l.id)}
              style={{
                font: 'inherit', fontSize: 'var(--text-sm)',
                padding: '5px 11px', borderRadius: 999, cursor: 'pointer',
                border: '1px solid ' + (l.id === lensId ? 'var(--signal)' : 'var(--ink-100)'),
                background: l.id === lensId ? 'var(--signal-tint)' : 'transparent',
                color: l.id === lensId ? 'var(--signal)' : 'var(--fg-muted)',
                fontWeight: l.id === lensId ? 'var(--weight-medium)' : 'var(--weight-regular)',
              }}>{l.label}</button>
          ))}
        </div>
        {tab === 'skolor' && (
          <>
            <Eyebrow>Region</Eyebrow>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, margin: '8px 0 14px' }}>
              {['alla', 'New England', 'Bay Area', 'Houston'].map(rg => (
                <button key={rg} onClick={() => setRegion(rg)}
                  style={{
                    font: 'inherit', fontSize: 'var(--text-sm)',
                    padding: '5px 11px', borderRadius: 999, cursor: 'pointer',
                    border: '1px solid ' + (rg === region ? 'var(--signal)' : 'var(--ink-100)'),
                    background: rg === region ? 'var(--signal-tint)' : 'transparent',
                    color: rg === region ? 'var(--signal)' : 'var(--fg-muted)',
                    fontWeight: rg === region ? 'var(--weight-medium)' : 'var(--weight-regular)',
                  }}>{rg === 'alla' ? 'Alla' : rg}</button>
              ))}
            </div>
          </>
        )}
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
          <Input value={q} onChange={setQ} placeholder="Sök namn, ort, konferens…" size="sm" />
          <span style={{ marginLeft: 'auto', fontSize: 'var(--text-xs)', color: 'var(--fg-muted)' }}>
            {rows.length} rader · {graded} med egen bedömning
          </span>
        </div>
      </Card>

      <Card pad={0}>
        <div style={{ overflowX: 'auto' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 'var(--text-sm)' }}>
            <thead>
              <tr style={{ borderBottom: '1px solid var(--ink-100)' }}>
                <th style={{ padding: '10px 10px' }} />
                {cols.map(col => (
                  <SortHeader key={col.key} col={col} sort={sort} onSort={onSort} />
                ))}
              </tr>
            </thead>
            <tbody>
              {rows.map((r, i) => (
                <tr key={r.id} style={{ borderBottom: '1px solid var(--ink-50)' }}>
                  <td style={{ padding: '9px 10px', color: 'var(--ink-300)',
                               fontFamily: 'var(--font-mono)', fontSize: 'var(--text-2xs)' }}>{i + 1}</td>
                  <td style={{ padding: '9px 10px', fontWeight: 'var(--weight-medium)' }}>
                    {r.url
                      ? <a href={r.url} target="_blank" rel="noopener noreferrer"
                           style={{ color: 'var(--fg)', textDecoration: 'none' }}>{r.name}</a>
                      : r.name}
                  </td>
                  <td style={{ padding: '9px 10px', color: 'var(--fg-muted)', whiteSpace: 'nowrap' }}>{r.loc || '–'}</td>
                  {['aca', 'fb', 'hk'].map(a => (
                    <td key={a} style={{ padding: '9px 10px', textAlign: 'center' }}>
                      <GradeCell value={r[a]} editable={false} />
                    </td>
                  ))}
                  <td style={{ padding: '9px 10px', textAlign: 'center' }}>
                    <GradeCell value={r.mine} editable={isAdmin} onSet={v => setGrade(r, v)} />
                  </td>
                  <td style={{ padding: '9px 10px', textAlign: 'center',
                               fontFamily: 'var(--font-mono)', color: 'var(--ink-700)' }}>
                    {r._fit == null ? '–' : r._fit.toFixed(1)}
                  </td>
                  {tab === 'skolor' ? (
                    <>
                      <td style={{ padding: '9px 10px', fontFamily: 'var(--font-mono)',
                                   fontSize: 'var(--text-xs)', color: 'var(--fg-muted)', whiteSpace: 'nowrap' }}>
                        {r.fee ? '$' + r.fee.toLocaleString('en-US') : '–'}
                      </td>
                      <td style={{ padding: '9px 10px', color: 'var(--fg-muted)', whiteSpace: 'nowrap' }}>
                        {r.region || '–'}
                      </td>
                      <td style={{ padding: '9px 10px' }}>
                        {r.entry ? <Pill>{r.entry}</Pill> : null}
                      </td>
                    </>
                  ) : (
                    <>
                      <td style={{ padding: '9px 10px', color: 'var(--fg-muted)' }}>{r.div || '–'}</td>
                      <td style={{ padding: '9px 10px', color: 'var(--fg-muted)' }}>{r.conf || '–'}</td>
                    </>
                  )}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>

      <p style={{ fontSize: 'var(--text-xs)', color: 'var(--fg-muted)', marginTop: 14, lineHeight: 'var(--leading-norm)' }}>
        Aka / FB / HK är forskade betyg. <strong>Min</strong> är din egen bedömning — klicka för att ändra,
        den sparas direkt och väger in i Fit under varje lins. Resonemanget bakom urvalet finns i
        <code style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--text-2xs)' }}> Family/Football/School/</code>.
      </p>
    </div>
  );
}

window.SkolorScreen = SkolorScreen;
