/* sasongsplan.jsx — the multi-year planning surface.
   Per-member: dream → 3-year vision → 1-year target → 5 key tests → 4-season
   target matrix. All inline-editable. Saves to Supabase on blur. */
/* global React, MEMBERS, TESTS, Eyebrow, Avatar, Card, Pill, Button, Input,
   SectionHeader, getGoalTrack, saveGoalTrack, getSeasonTargets, getKeyTestIds,
   getSeasonTarget, addKeyTest, removeKeyTest, saveSeasonTarget,
   nextFourSeasons, getTest, latestAttempt, getMemberChallenges */
const { useState, useMemo, useEffect } = React;

// ============================================================================
// SasongsplanView — main view, rendered when Tester is toggled to "Säsongsplan"
// ============================================================================
function SasongsplanView({ memberId, isMobile }) {
  const [, bump] = useState(0);
  const refresh = () => bump(b => b + 1);
  const member = MEMBERS.find(m => m.id === memberId);
  const canEdit = !!(window.canEdit && window.canEdit(memberId));

  const track = window.getGoalTrack(memberId);
  const keyTestIds = window.getKeyTestIds(memberId);
  const seasons = window.planningWindowSeasons
    ? window.planningWindowSeasons()
    : window.nextFourSeasons();
  const currentSeasonId = window.ACTIVE_SEASON_ID;
  const [suggestState, setSuggestState] = useState({ busy: false, error: null });

  // Baselines must exist for every key test before we ask the coach to suggest
  // targets — grounding the prompt in real data is what makes the suggestions
  // useful. A key test "has a baseline" when getMemberCurrentBaseline returns
  // a numeric value.
  const baselineStatus = keyTestIds.map(testId => ({
    testId,
    test: window.getTest ? window.getTest(testId) : null,
    value: window.getMemberCurrentBaseline
      ? window.getMemberCurrentBaseline(memberId, testId)
      : null,
  }));
  const missingBaselines = baselineStatus.filter(b => b.value == null && b.test);
  const hasAllBaselines = keyTestIds.length > 0 && missingBaselines.length === 0;

  if (!member) return null;

  return (
    <div style={{ padding: '24px 16px 80px', maxWidth: 1280, margin: '0 auto' }}>
      {/* Header */}
      <div style={{ marginBottom: 24 }}>
        <Eyebrow style={{ marginBottom: 8 }}>Säsongsplan</Eyebrow>
        <h1 style={{ margin: 0, fontFamily: 'var(--font-sans)', fontSize: 32, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1.15 }}>
          <span style={{ color: member.color }}>{member.name}</span>s plan
        </h1>
        <p style={{ margin: '8px 0 0', maxWidth: 620, fontSize: 13, color: 'var(--fg-muted)', lineHeight: 1.55 }}>
          Drömmen ger riktningen. 3-årsvisionen sätter ribban. 1-årsmålet är var du
          behöver vara om 12 månader. Och säsongsmålen är de konkreta milstolparna
          längs vägen.
        </p>
      </div>

      {/* Narrative layer */}
      <GoalTrackEditor memberId={memberId} member={member} track={track} canEdit={canEdit} onChange={refresh} />

      {/* Key tests + target matrix */}
      <div style={{ marginTop: 28 }}>
        <SectionHeader eyebrow="Nyckel-tester" title="5 viktigaste testerna" />
        <KeyTestsPicker
          memberId={memberId}
          keyTestIds={keyTestIds}
          canEdit={canEdit}
          onChange={refresh}
        />
      </div>

      <div style={{ marginTop: 28 }}>
        <SectionHeader
          eyebrow="Säsongsmål"
          title={`Innevarande + ${seasons.length - 1} säsonger framåt`}
          action={
            canEdit && keyTestIds.length > 0 && (
              <Button
                kind="primary"
                size="sm"
                disabled={suggestState.busy || !hasAllBaselines}
                onClick={() => suggestTargets(memberId, setSuggestState, refresh)}
                title={!hasAllBaselines ? 'Fyll i nuläge för alla tester först — coachen behöver dem för att föreslå realistiska mål.' : undefined}
              >
                {suggestState.busy ? 'Coach tänker…' : '✦ Föreslå mål'}
              </Button>
            )
          }
        />
        {canEdit && keyTestIds.length > 0 && !hasAllBaselines && (
          <div style={{
            fontSize: 12, color: 'var(--fg-muted)', marginBottom: 8, lineHeight: 1.5,
            background: 'var(--ink-25)', padding: '8px 12px', borderRadius: 4,
            borderLeft: `3px solid ${member.color || 'var(--signal)'}`,
          }}>
            Fyll i nuläge ({missingBaselines.length} kvar) i kolumnen längst till vänster så coachen
            kan föreslå realistiska mål baserat på var {member.name} faktiskt står idag.
          </div>
        )}
        {suggestState.error && (
          <div style={{ fontSize: 12, color: 'var(--danger)', marginBottom: 8, fontFamily: 'var(--font-mono)' }}>
            {suggestState.error}
          </div>
        )}
        {keyTestIds.length === 0 ? (
          <Card pad={24} style={{ textAlign: 'center', color: 'var(--fg-muted)' }}>
            <div style={{ fontSize: 14, marginBottom: 8 }}>Inga nyckel-tester valda än.</div>
            <div style={{ fontSize: 12, color: 'var(--fg-subtle)' }}>
              Lägg till tester ovan, sedan kan du sätta säsongsmål här.
            </div>
          </Card>
        ) : (
          <TargetMatrix
            memberId={memberId}
            keyTestIds={keyTestIds}
            seasons={seasons}
            currentSeasonId={currentSeasonId}
            canEdit={canEdit}
            onChange={refresh}
            isMobile={isMobile}
          />
        )}
        {keyTestIds.length > 0 && currentSeasonId && (
          <div style={{ marginTop: 10, fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-subtle)', letterSpacing: '0.04em', lineHeight: 1.55 }}>
            Mål för innevarande säsong skapas som utmaningar och låses när säsongen slutar.<br />
            Coachens förslag justerar bara de tre kommande säsongerna — innevarande mål rörs inte.
          </div>
        )}
      </div>
    </div>
  );
}

// ============================================================================
// GoalTrackEditor — dream + 3yr vision + 1yr target editable text areas
// ============================================================================
function GoalTrackEditor({ memberId, member, track, canEdit, onChange }) {
  const t = track || { dream: '', three_year_vision: '', one_year_target: '' };
  const save = (patch) => {
    window.saveGoalTrack(memberId, patch);
    onChange();
  };
  return (
    <Card pad={0} style={{ marginTop: 12 }}>
      <NarrativeField
        eyebrow="Dröm"
        hint="Vad är drömmen? T.ex. 'Top-10 NHL-spelare', 'Världselit i handboll', 'Stark och hälsosam livet ut'."
        value={t.dream}
        onSave={(v) => save({ dream: v })}
        canEdit={canEdit}
        memberColor={member.color}
      />
      <Hr />
      <NarrativeField
        eyebrow="3-årsvision"
        hint="Var vill du vara om 3 år? Konkret. T.ex. 'Topp av U13 regionalt, vertikal 40cm, NHL Combine-nivå för åldern'."
        value={t.three_year_vision}
        onSave={(v) => save({ three_year_vision: v })}
        canEdit={canEdit}
        memberColor={member.color}
      />
      <Hr />
      <NarrativeField
        eyebrow="1-årsmål"
        hint="Var behöver du vara om 12 månader för att vara på spår? T.ex. 'Regional U11-utvecklingstrupp, Cooper 2400m, 6 pull-ups'."
        value={t.one_year_target}
        onSave={(v) => save({ one_year_target: v })}
        canEdit={canEdit}
        memberColor={member.color}
      />
    </Card>
  );
}

function Hr() {
  return <div style={{ height: 1, background: 'var(--border-faint)' }} />;
}

function NarrativeField({ eyebrow, hint, value, onSave, canEdit, memberColor }) {
  const [draft, setDraft] = useState(value || '');
  const [editing, setEditing] = useState(false);

  // Keep draft in sync if the underlying value changes (e.g. async load)
  useEffect(() => { setDraft(value || ''); }, [value]);

  const onBlur = () => {
    setEditing(false);
    if ((draft || '') !== (value || '')) {
      onSave(draft);
    }
  };

  return (
    <div style={{ padding: '18px 22px' }}>
      <Eyebrow style={{ marginBottom: 6 }}>{eyebrow}</Eyebrow>
      {!editing && !draft && (
        <div
          onClick={() => canEdit && setEditing(true)}
          style={{
            fontSize: 13, color: 'var(--fg-subtle)', fontStyle: 'italic',
            cursor: canEdit ? 'text' : 'default',
            padding: '8px 0', lineHeight: 1.5,
          }}
        >
          {canEdit ? hint : '(inget angivet)'}
        </div>
      )}
      {(editing || draft) && (
        <textarea
          value={draft}
          readOnly={!canEdit}
          onChange={e => setDraft(e.target.value)}
          onFocus={() => setEditing(true)}
          onBlur={onBlur}
          placeholder={hint}
          rows={Math.max(2, Math.min(6, draft.split('\n').length + 1))}
          style={{
            width: '100%', resize: 'vertical',
            fontFamily: 'var(--font-sans)', fontSize: 15, lineHeight: 1.55,
            color: 'var(--fg)', background: 'transparent',
            border: 'none', outline: 'none', padding: '6px 0',
            borderLeft: editing ? `3px solid ${memberColor || 'var(--signal)'}` : '3px solid transparent',
            paddingLeft: 10, marginLeft: -10,
            transition: 'border-color 120ms',
            boxSizing: 'border-box',
          }}
        />
      )}
    </div>
  );
}

// ============================================================================
// KeyTestsPicker — pick the 5 (or so) "north-star" tests for this member
// ============================================================================
function KeyTestsPicker({ memberId, keyTestIds, canEdit, onChange }) {
  const [picking, setPicking] = useState(false);
  const allTests = TESTS.filter(t => !t.archived);
  const keyTests = keyTestIds.map(id => allTests.find(t => t.id === id)).filter(Boolean);
  const availableToAdd = allTests.filter(t => !keyTestIds.includes(t.id));

  return (
    <Card pad={16}>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
        {keyTests.map(t => (
          <Pill
            key={t.id}
            bg="var(--ink-50)"
            color="var(--fg)"
            style={{ padding: '6px 12px', fontSize: 12, textTransform: 'none', letterSpacing: 0, gap: 8 }}
          >
            <span style={{ fontWeight: 500 }}>{t.name}</span>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-subtle)' }}>{t.unit}</span>
            {canEdit && (
              <button
                onClick={() => { window.removeKeyTest(memberId, t.id); onChange(); }}
                style={{ background: 'none', border: 'none', color: 'var(--fg-muted)', cursor: 'pointer', padding: 0, marginLeft: 4, fontSize: 13, lineHeight: 1 }}
                title="Ta bort"
              >×</button>
            )}
          </Pill>
        ))}

        {canEdit && (
          <button
            onClick={() => setPicking(p => !p)}
            disabled={availableToAdd.length === 0}
            style={{
              fontFamily: 'var(--font-sans)', fontSize: 12, fontWeight: 500,
              padding: '6px 12px', borderRadius: 4,
              border: '1px dashed var(--border-strong)', background: 'var(--bg-raised)',
              color: 'var(--fg-muted)', cursor: availableToAdd.length === 0 ? 'not-allowed' : 'pointer',
              opacity: availableToAdd.length === 0 ? 0.4 : 1,
            }}
          >+ Lägg till test</button>
        )}
      </div>

      {picking && (
        <div style={{ marginTop: 12, padding: 12, background: 'var(--ink-25)', borderRadius: 4 }}>
          <Eyebrow style={{ marginBottom: 8 }}>Välj test att lägga till</Eyebrow>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 6 }}>
            {availableToAdd.map(t => (
              <button
                key={t.id}
                onClick={() => { window.addKeyTest(memberId, t.id); setPicking(false); onChange(); }}
                style={{
                  textAlign: 'left', padding: '8px 10px',
                  background: 'var(--bg-raised)', border: '1px solid var(--border)', borderRadius: 4,
                  cursor: 'pointer', fontFamily: 'var(--font-sans)',
                }}
              >
                <div style={{ fontSize: 13, fontWeight: 500 }}>{t.name}</div>
                <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--fg-subtle)', marginTop: 2 }}>
                  {t.cat} · {t.unit} · {t.dir === 'lower' ? 'lägre = bättre' : 'högre = bättre'}
                </div>
              </button>
            ))}
          </div>
        </div>
      )}

      {!canEdit && keyTests.length === 0 && (
        <div style={{ fontSize: 12, color: 'var(--fg-subtle)', fontStyle: 'italic' }}>
          Inga nyckel-tester valda.
        </div>
      )}
    </Card>
  );
}

// ============================================================================
// TargetMatrix — 5 tests × 4 seasons grid with inline-editable target values
// ============================================================================
function TargetMatrix({ memberId, keyTestIds, seasons, currentSeasonId, canEdit, onChange, isMobile }) {
  const tests = keyTestIds.map(id => window.getTest(id)).filter(Boolean);
  if (isMobile) {
    return <TargetMatrixMobile memberId={memberId} tests={tests} seasons={seasons} currentSeasonId={currentSeasonId} canEdit={canEdit} onChange={onChange} />;
  }
  return <TargetMatrixDesktop memberId={memberId} tests={tests} seasons={seasons} currentSeasonId={currentSeasonId} canEdit={canEdit} onChange={onChange} />;
}

function TargetMatrixDesktop({ memberId, tests, seasons, currentSeasonId, canEdit, onChange }) {
  // Grid: first column = test name + editable baseline ("nuläge"), then one
  // column per season, then a Status column at the right.
  const grid = `minmax(200px, 1.8fr) repeat(${seasons.length}, minmax(110px, 1fr)) minmax(150px, 1.1fr)`;

  return (
    <Card pad={0} style={{ overflow: 'hidden' }}>
      {/* Header row */}
      <div style={{
        display: 'grid', gridTemplateColumns: grid, gap: 0,
        padding: '12px 16px',
        borderBottom: '1px solid var(--border)',
        background: 'var(--ink-25)',
        alignItems: 'center',
      }}>
        <div><Eyebrow>Test · nuläge</Eyebrow></div>
        {seasons.map(s => {
          const isCurrent = s.id === currentSeasonId;
          return (
            <div key={s.id} style={{ textAlign: 'right' }}>
              <Eyebrow style={{ color: isCurrent ? 'var(--signal)' : undefined }}>
                {s.name}{isCurrent ? ' · NU' : ''}
              </Eyebrow>
              {isCurrent && (
                <div style={{
                  fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--fg-subtle)',
                  letterSpacing: '0.06em', marginTop: 2, textTransform: 'uppercase',
                }}>
                  låst för säsongen
                </div>
              )}
            </div>
          );
        })}
        <div style={{ textAlign: 'right' }}><Eyebrow>Status</Eyebrow></div>
      </div>

      {/* Rows */}
      {tests.map((t, i) => {
        const baseline = window.getMemberCurrentBaseline
          ? window.getMemberCurrentBaseline(memberId, t.id)
          : null;
        const status = window.computeTestStatus
          ? window.computeTestStatus(memberId, t.id)
          : null;
        return (
          <div key={t.id} style={{
            display: 'grid', gridTemplateColumns: grid, gap: 0,
            padding: '14px 16px',
            alignItems: 'center',
            borderBottom: i < tests.length - 1 ? '1px solid var(--border-faint)' : 'none',
          }}>
            {/* Test name + editable baseline */}
            <div>
              <div style={{ fontSize: 14, fontWeight: 500 }}>{t.name}</div>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-subtle)', marginTop: 2 }}>
                {t.cat} · {t.unit} · {t.dir === 'lower' ? 'lägre = bättre' : 'högre = bättre'}
              </div>
              <div style={{ marginTop: 6, display: 'flex', alignItems: 'center', gap: 6 }}>
                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-subtle)', letterSpacing: '0.04em' }}>
                  NU
                </span>
                <BaselineCell
                  value={baseline}
                  unit={t.unit}
                  canEdit={canEdit}
                  onChange={(v) => {
                    window.setMemberCurrentBaseline(memberId, t.id, v);
                    onChange();
                  }}
                />
              </div>
            </div>

            {/* Per-season target cells */}
            {seasons.map(s => {
              const target = window.getSeasonTarget(memberId, t.id, s.id);
              return (
                <div key={s.id} style={{ textAlign: 'right' }}>
                  <TargetCell
                    value={target ? target.target_value : null}
                    unit={t.unit}
                    onChange={(v) => { window.saveSeasonTarget(memberId, t.id, s.id, v); onChange(); }}
                    canEdit={canEdit}
                  />
                </div>
              );
            })}

            {/* Status column */}
            <div style={{ textAlign: 'right' }}>
              <StatusBadge status={status} />
            </div>
          </div>
        );
      })}
    </Card>
  );
}

function TargetMatrixMobile({ memberId, tests, seasons, currentSeasonId, canEdit, onChange }) {
  // On mobile: one season at a time with a pager.
  const [seasonIdx, setSeasonIdx] = useState(0);
  const season = seasons[seasonIdx];
  if (!season) return null;

  return (
    <Card pad={0} style={{ overflow: 'hidden' }}>
      {/* Pager */}
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '10px 14px', borderBottom: '1px solid var(--border)', background: 'var(--ink-25)',
      }}>
        <button
          onClick={() => setSeasonIdx(i => Math.max(0, i - 1))}
          disabled={seasonIdx === 0}
          style={pagerBtnStyle(seasonIdx === 0)}
        >‹</button>
        <div style={{ textAlign: 'center' }}>
          <Eyebrow>Säsong {seasonIdx + 1} av {seasons.length}</Eyebrow>
          <div style={{ fontSize: 14, fontWeight: 500, marginTop: 2 }}>
            {season.name}
            {season.id === currentSeasonId && (
              <span style={{ marginLeft: 6, color: 'var(--signal)', fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.08em' }}>· NU</span>
            )}
          </div>
          {season.id === currentSeasonId && (
            <div style={{
              fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--fg-subtle)',
              letterSpacing: '0.06em', marginTop: 2, textTransform: 'uppercase',
            }}>
              låst för säsongen
            </div>
          )}
        </div>
        <button
          onClick={() => setSeasonIdx(i => Math.min(seasons.length - 1, i + 1))}
          disabled={seasonIdx === seasons.length - 1}
          style={pagerBtnStyle(seasonIdx === seasons.length - 1)}
        >›</button>
      </div>

      {/* Per-test rows */}
      {tests.map((t, i) => {
        const baseline = window.getMemberCurrentBaseline
          ? window.getMemberCurrentBaseline(memberId, t.id)
          : null;
        const target = window.getSeasonTarget(memberId, t.id, season.id);
        const status = window.computeTestStatus
          ? window.computeTestStatus(memberId, t.id)
          : null;
        return (
          <div key={t.id} style={{
            padding: '12px 14px',
            borderBottom: i < tests.length - 1 ? '1px solid var(--border-faint)' : 'none',
          }}>
            <div style={{
              display: 'grid', gridTemplateColumns: '1fr 88px', gap: 12,
              alignItems: 'center',
            }}>
              <div>
                <div style={{ fontSize: 13, fontWeight: 500 }}>{t.name}</div>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-subtle)', marginTop: 2 }}>
                  {t.unit} · {t.dir === 'lower' ? 'lägre = bättre' : 'högre = bättre'}
                </div>
                <div style={{ marginTop: 6, display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-subtle)', letterSpacing: '0.04em' }}>NU</span>
                  <BaselineCell
                    value={baseline}
                    unit={t.unit}
                    canEdit={canEdit}
                    onChange={(v) => {
                      window.setMemberCurrentBaseline(memberId, t.id, v);
                      onChange();
                    }}
                  />
                </div>
              </div>
              <div style={{ textAlign: 'right' }}>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--fg-subtle)', letterSpacing: '0.06em', marginBottom: 2 }}>MÅL</div>
                <TargetCell
                  value={target ? target.target_value : null}
                  unit={t.unit}
                  onChange={(v) => { window.saveSeasonTarget(memberId, t.id, season.id, v); onChange(); }}
                  canEdit={canEdit}
                />
              </div>
            </div>
            {status && (
              <div style={{ marginTop: 8 }}>
                <StatusBadge status={status} />
              </div>
            )}
          </div>
        );
      })}
    </Card>
  );
}

function pagerBtnStyle(disabled) {
  return {
    width: 36, height: 36, borderRadius: 4,
    border: '1px solid var(--border-strong)', background: 'var(--bg-raised)',
    color: disabled ? 'var(--fg-faint)' : 'var(--fg)',
    cursor: disabled ? 'not-allowed' : 'pointer',
    fontSize: 18, fontWeight: 500,
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
  };
}

// ============================================================================
// BaselineCell — inline-editable "where am I right now" number. Behaves like
// TargetCell but shows an obvious "+ ange" affordance when empty since this is
// the gate that unlocks "Föreslå mål".
// ============================================================================
function BaselineCell({ value, unit, onChange, canEdit }) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(value != null ? String(value) : '');

  useEffect(() => { setDraft(value != null ? String(value) : ''); }, [value]);

  const commit = () => {
    setEditing(false);
    if (draft === '' && value == null) return;
    const n = draft === '' ? null : Number(draft);
    if (n != null && !isNaN(n) && n !== value) onChange(n);
  };

  if (!canEdit) {
    return (
      <span style={{
        fontFamily: 'var(--font-mono)', fontSize: 12,
        color: value == null ? 'var(--fg-faint)' : 'var(--fg)',
        fontVariantNumeric: 'tabular-nums',
      }}>
        {value == null ? '—' : `${value} ${unit}`}
      </span>
    );
  }

  if (editing) {
    return (
      <input
        type="number"
        step="0.01"
        autoFocus
        value={draft}
        onChange={e => setDraft(e.target.value)}
        onBlur={commit}
        onKeyDown={e => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') { setDraft(value != null ? String(value) : ''); setEditing(false); } }}
        placeholder={unit}
        style={{
          fontFamily: 'var(--font-mono)', fontSize: 12, fontVariantNumeric: 'tabular-nums',
          width: 90, textAlign: 'left',
          padding: '3px 6px', border: '1px solid var(--signal)', borderRadius: 3,
          outline: 'none', background: '#fff', color: 'var(--fg)',
          boxShadow: '0 0 0 3px rgba(14,133,67,0.18)',
        }}
      />
    );
  }

  if (value == null) {
    return (
      <button
        onClick={() => setEditing(true)}
        style={{
          fontFamily: 'var(--font-sans)', fontSize: 11, fontWeight: 500,
          background: 'var(--bg-raised)',
          border: '1px dashed var(--border-strong)',
          color: 'var(--fg-muted)',
          cursor: 'pointer',
          padding: '2px 8px', borderRadius: 3,
        }}
        onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--signal)'; e.currentTarget.style.color = 'var(--signal)'; }}
        onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border-strong)'; e.currentTarget.style.color = 'var(--fg-muted)'; }}
      >
        + ange
      </button>
    );
  }

  return (
    <button
      onClick={() => setEditing(true)}
      style={{
        fontFamily: 'var(--font-mono)', fontSize: 12, fontVariantNumeric: 'tabular-nums',
        background: 'none', border: 'none', cursor: 'pointer',
        color: 'var(--fg)', padding: '2px 6px', borderRadius: 3,
      }}
      onMouseEnter={e => e.currentTarget.style.background = 'var(--ink-25)'}
      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
      title="Klicka för att uppdatera"
    >
      {value} <span style={{ color: 'var(--fg-subtle)' }}>{unit}</span>
    </button>
  );
}

// ============================================================================
// StatusBadge — shows "where the latest performance stacks against the goal
// and ambition". Driven by window.computeTestStatus().
// ============================================================================
function StatusBadge({ status }) {
  if (!status) {
    return (
      <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-faint)' }}>—</span>
    );
  }
  // Color palette per kind. Falls back to neutral for unknown kinds.
  const palette = {
    no_data:           { bg: 'var(--ink-25)',          fg: 'var(--fg-muted)',  border: 'var(--border)' },
    no_target:         { bg: 'var(--ink-25)',          fg: 'var(--fg-muted)',  border: 'var(--border)' },
    at_baseline:       { bg: 'var(--ink-25)',          fg: 'var(--fg)',        border: 'var(--border-strong)' },
    partial:           { bg: 'var(--ink-25)',          fg: 'var(--fg)',        border: 'var(--border)' },
    regressed:         { bg: 'rgba(192,57,43,0.10)',   fg: '#a93226',          border: 'rgba(192,57,43,0.45)' },
    behind:            { bg: 'rgba(214,137,16,0.10)',  fg: '#a36808',          border: 'rgba(214,137,16,0.45)' },
    on_track:          { bg: 'rgba(14,133,67,0.10)',   fg: '#0e8543',          border: 'rgba(14,133,67,0.40)' },
    on_target:         { bg: 'rgba(14,133,67,0.18)',   fg: '#0e6f3b',          border: 'rgba(14,133,67,0.55)' },
    exceeded_ambition: { bg: 'rgba(14,133,67,0.28)',   fg: '#0a5a30',          border: 'rgba(14,133,67,0.70)' },
  };
  const p = palette[status.kind] || palette.no_target;
  return (
    <div style={{ display: 'inline-flex', flexDirection: 'column', alignItems: 'flex-end', gap: 3, textAlign: 'right' }}>
      <span style={{
        fontFamily: 'var(--font-sans)', fontSize: 11, fontWeight: 500,
        background: p.bg, color: p.fg,
        border: `1px solid ${p.border}`,
        padding: '3px 8px', borderRadius: 999,
        whiteSpace: 'nowrap',
      }}>
        {status.label}
      </span>
      {status.detail && (
        <span style={{
          fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-subtle)',
          fontVariantNumeric: 'tabular-nums', lineHeight: 1.3,
        }}>
          {status.detail}
        </span>
      )}
    </div>
  );
}

// ============================================================================
// TargetCell — inline-editable number cell
// ============================================================================
function TargetCell({ value, unit, onChange, canEdit }) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(value != null ? String(value) : '');

  useEffect(() => { setDraft(value != null ? String(value) : ''); }, [value]);

  const commit = () => {
    setEditing(false);
    if (draft === '' && value == null) return;
    const n = draft === '' ? null : Number(draft);
    if (n !== value && (n == null || !isNaN(n))) onChange(n);
  };

  if (!canEdit) {
    return (
      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 13, color: value == null ? 'var(--fg-faint)' : 'var(--fg)', fontVariantNumeric: 'tabular-nums' }}>
        {value == null ? '—' : value}
      </div>
    );
  }

  if (editing) {
    return (
      <input
        type="number"
        step="0.01"
        autoFocus
        value={draft}
        onChange={e => setDraft(e.target.value)}
        onBlur={commit}
        onKeyDown={e => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') { setDraft(value != null ? String(value) : ''); setEditing(false); } }}
        style={{
          fontFamily: 'var(--font-mono)', fontSize: 13, fontVariantNumeric: 'tabular-nums',
          width: 80, textAlign: 'right',
          padding: '4px 6px', border: '1px solid var(--signal)', borderRadius: 3,
          outline: 'none', background: '#fff', color: 'var(--fg)',
          boxShadow: '0 0 0 3px rgba(14,133,67,0.18)',
        }}
      />
    );
  }

  return (
    <button
      onClick={() => setEditing(true)}
      style={{
        fontFamily: 'var(--font-mono)', fontSize: 13, fontVariantNumeric: 'tabular-nums',
        background: 'none', border: 'none', cursor: 'pointer',
        color: value == null ? 'var(--fg-faint)' : 'var(--fg)',
        padding: '4px 6px', borderRadius: 3,
      }}
      onMouseEnter={e => e.currentTarget.style.background = 'var(--ink-25)'}
      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
    >
      {value == null ? '—' : value}
    </button>
  );
}

// ============================================================================
// suggestTargets — call the coach Edge Function for AI-proposed targets
// ============================================================================
async function suggestTargets(memberId, setState, refresh) {
  setState({ busy: true, error: null });
  try {
    const member = MEMBERS.find(m => m.id === memberId);
    if (!member) throw new Error('Medlem hittades inte');
    const { data: { session } } = await window.sb.auth.getSession();
    if (!session) throw new Error('Inte inloggad');
    const FN_URL = window.SUPABASE_URL + '/functions/v1/coach';
    const resp = await fetch(FN_URL, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${session.access_token}`,
        'Content-Type': 'application/json',
        'apikey': window.SUPABASE_ANON_KEY,
      },
      body: JSON.stringify({ action: 'suggest_targets', memberId: member.db_id }),
    });
    if (!resp.ok) {
      const txt = await resp.text();
      throw new Error(`Förslag misslyckades (${resp.status}): ${txt.slice(0, 200)}`);
    }
    const j = await resp.json();
    const suggestions = j.suggestions || [];
    if (suggestions.length === 0) throw new Error('Coachen returnerade inga förslag');

    // Apply each suggestion to season_target. The current season's target is
    // locked once set — once the user (or coach) commits to a goal for the
    // ongoing season, "Föreslå mål" can only propose values for the three
    // upcoming seasons. End-of-season results will drive future adjustments.
    let skippedCurrent = 0;
    for (const s of suggestions) {
      if (s.test_id && s.season_id && s.value != null) {
        if (s.season_id === window.ACTIVE_SEASON_ID) {
          const existing = window.getSeasonTarget(memberId, s.test_id, s.season_id);
          if (existing && existing.target_value != null) {
            skippedCurrent++;
            continue;
          }
        }
        window.saveSeasonTarget(memberId, s.test_id, s.season_id, Number(s.value), {
          notes: s.rationale || '',
          source: 'coach_suggested',
        });
      }
    }
    if (skippedCurrent > 0) {
      console.log(`[suggest_targets] skipped ${skippedCurrent} current-season targets (locked)`);
    }
    setState({ busy: false, error: null });
    refresh();
  } catch (e) {
    console.error('[suggest_targets]', e);
    setState({ busy: false, error: e.message || String(e) });
  }
}

window.SasongsplanView = SasongsplanView;
