// Tasks — タスク／滞り一覧: 🟠通常・🔴重大、ボール保持者別。やるべきこと＝あるべき事実の欠落（種類C事実）.
//
// 盤面・TODO-7(Codex起票・docs/13-task-board.md): severityは固定文字列をやめ、
// store.jsxのtodoSeverity(SLA監視・0049・決-20/24の判定を1か所に集約した関数)で
// 実計算する。TASKS(data.jsx)自体はmarker/sev/caseSlaという「素データ」だけを持ち、
// 表示用のseverity文字列はここで都度計算する(決-11「StatusBoard/Tasks/Queuesは
// 残すが復活作業は積まない」= 最小限の置き換えにとどめる)。

// 期日の並び替え専用(表示文字列の素朴な数値化。判定には使わない)。
function tasksDueRank(t) {
  const s = String((t && t.due) || '');
  if (s.indexOf('本日') === 0) return -1;
  const m = s.match(/(\d{4})\/(\d{1,2})\/(\d{1,2})/);
  return m ? Number(m[1]) * 10000 + Number(m[2]) * 100 + Number(m[3]) : Infinity;
}

function TaskRow({ t, onOpen }) {
  return (
    <div onClick={() => onOpen && onOpen(t.case)} style={{
      display: 'flex', alignItems: 'flex-start', gap: 12, padding: '11px 14px', borderBottom: '1px solid var(--border)',
      cursor: 'pointer', transition: 'background var(--duration-fast) var(--easing)',
    }}
      onMouseEnter={e => e.currentTarget.style.background = 'var(--accent)'}
      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
      <div style={{ width: 16, display: 'flex', justifyContent: 'center', paddingTop: 2, flexShrink: 0 }}>
        <input type="checkbox" style={{ width: 14, height: 14, accentColor: 'var(--brand)', cursor: 'pointer' }} onClick={e => e.stopPropagation()} />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          {t.severity !== 'normal' && <SeverityBadge level={t.severity} />}
          <span style={{ fontSize: 'var(--text-body-md)', fontWeight: 600 }}>{t.title}</span>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4, flexWrap: 'wrap' }}>
          <span className="code" style={{ fontSize: 'var(--text-caption)', color: 'var(--brand)' }}>{t.case}</span>
          <span style={{ fontSize: 'var(--text-caption)', color: 'var(--muted-foreground)' }}>{t.caseName}</span>
          <span style={{ fontSize: 'var(--text-caption)', color: 'var(--foreground-subtle)', fontWeight: 600, padding: '0 5px', height: 15, lineHeight: '15px', background: 'var(--muted)', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border)' }}>{t.track}</span>
          <span style={{ fontSize: 'var(--text-caption)', color: 'var(--foreground-subtle)' }}>{t.gen === 'auto' ? '自動生成' : '手動'}</span>
        </div>
        {t.waitLabel && <div style={{ fontSize: 'var(--text-caption)', color: 'var(--warning)', marginTop: 4 }}>{t.waitLabel}</div>}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 5, flexShrink: 0 }}>
        <span className="mono" style={{ fontSize: 'var(--text-body-sm)', fontWeight: 600, color: t.due === '本日' || t.due === '本日 17:00' ? 'var(--destructive)' : 'var(--muted-foreground)' }}>{t.due}</span>
        <BallChip who={t.ball} />
      </div>
    </div>
  );
}

function Tasks({ onOpenCase }) {
  const [ball, setBall] = React.useState('all');
  const [onlyStall, setOnlyStall] = React.useState(false);

  // 盤面・TODO-7: severityはTASKSの固定文字列ではなく、store.jsxのtodoSeverityで
  // 都度計算する(SLAしきい値はテナント設定・無ければ既定値。slaConfigと同じ
  // フォールバックにする)。
  const sla = window.slaConfig ? window.slaConfig(window.MStore.get()) : window.SLA_DEFAULTS;
  const today = new Date();
  const withSeverity = TASKS.map(t => {
    const waiting = !!(t.waiting || t.waitingSince || t.waitingReason);
    const waitLabel = t.waitLabel
      || (waiting && window.waitDisplay ? window.waitDisplay(t.waitingReason, t.waitingSince) : null);
    return {
      ...t,
      waitLabel,
      severity: window.todoSeverity({ ...t, waiting }, t.caseSla, sla, today),
    };
  });

  const counts = { self: 0, partner: 0, insurer: 0, client: 0 };
  withSeverity.forEach(t => { counts[t.ball] = (counts[t.ball] || 0) + 1; });
  const critical = withSeverity.filter(t => t.severity === 'critical').length;
  // 🟠通常の滞り = 重大ではないが既定期限超過(over)・迫っている/報告リズム超過(warn)。
  const normal = withSeverity.filter(t => t.severity === 'over' || t.severity === 'warn').length;

  let rows = withSeverity.filter(t => ball === 'all' ? true : t.ball === ball);
  if (onlyStall) rows = rows.filter(t => t.severity !== 'normal');
  // 並び順(TODO-7・決-11「次に何をやればいいか一発で分かる」): 重要度 → 期日 → 案件名。
  const sevRank = { critical: 0, over: 1, warn: 2, normal: 3 };
  rows = [...rows].sort((a, b) =>
    (sevRank[a.severity] ?? 3) - (sevRank[b.severity] ?? 3)
    || tasksDueRank(a) - tasksDueRank(b)
    || String(a.caseName).localeCompare(String(b.caseName), 'ja'));

  const ballFilters = [
    { id: 'all', label: 'すべて', n: withSeverity.length },
    { id: 'self', label: '自社', n: counts.self },
    { id: 'partner', label: '業者', n: counts.partner },
    { id: 'insurer', label: '保険会社', n: counts.insurer },
    { id: 'client', label: '依頼者', n: counts.client },
  ];

  return (
    <div style={{ padding: '20px 24px 32px 20px', maxWidth: 1080 }}>
      <div style={{ display: 'flex', gap: 12, marginBottom: 16 }}>
        <AfCard pad={14} style={{ flex: 1 }}>
          <div style={{ fontSize: 'var(--text-caption)', fontWeight: 600, letterSpacing: '0.08em', color: 'var(--muted-foreground)', textTransform: 'uppercase' }}>自社ボール</div>
          <div className="mono" style={{ fontSize: 'var(--text-display-lg)', fontWeight: 700, marginTop: 4 }}>{counts.self}<span style={{ fontSize: 13, fontWeight: 500, color: 'var(--muted-foreground)', marginLeft: 4 }}>件</span></div>
          <div style={{ fontSize: 'var(--text-caption)', color: 'var(--muted-foreground)', marginTop: 4 }}>自分が動くべきこと</div>
        </AfCard>
        <AfCard pad={14} style={{ flex: 1 }}>
          <div style={{ fontSize: 'var(--text-caption)', fontWeight: 600, letterSpacing: '0.08em', color: 'var(--muted-foreground)', textTransform: 'uppercase' }}>相手ボール</div>
          <div className="mono" style={{ fontSize: 'var(--text-display-lg)', fontWeight: 700, marginTop: 4 }}>{counts.partner + counts.insurer + counts.client}<span style={{ fontSize: 13, fontWeight: 500, color: 'var(--muted-foreground)', marginLeft: 4 }}>件</span></div>
          <div style={{ fontSize: 'var(--text-caption)', color: 'var(--muted-foreground)', marginTop: 4 }}>業者 {counts.partner} ・ 保険 {counts.insurer} ・ 依頼者 {counts.client}</div>
        </AfCard>
        <AfCard pad={14} style={{ flex: 1 }}>
          <div style={{ fontSize: 'var(--text-caption)', fontWeight: 600, letterSpacing: '0.08em', color: 'var(--warning)', textTransform: 'uppercase' }}>🟠 通常の滞り</div>
          <div className="mono" style={{ fontSize: 'var(--text-display-lg)', fontWeight: 700, marginTop: 4, color: 'var(--warning)' }}>{normal}<span style={{ fontSize: 13, fontWeight: 500, color: 'var(--muted-foreground)', marginLeft: 4 }}>件</span></div>
          <div style={{ fontSize: 'var(--text-caption)', color: 'var(--muted-foreground)', marginTop: 4 }}>約束期日／デフォルト期限 超過</div>
        </AfCard>
        <AfCard pad={14} style={{ flex: 1 }}>
          <div style={{ fontSize: 'var(--text-caption)', fontWeight: 600, letterSpacing: '0.08em', color: 'var(--destructive)', textTransform: 'uppercase' }}>🔴 重大の滞り</div>
          <div className="mono" style={{ fontSize: 'var(--text-display-lg)', fontWeight: 700, marginTop: 4, color: 'var(--destructive)' }}>{critical}<span style={{ fontSize: 13, fontWeight: 500, color: 'var(--muted-foreground)', marginLeft: 4 }}>件</span></div>
          <div style={{ fontSize: 'var(--text-caption)', color: 'var(--muted-foreground)', marginTop: 4 }}>約束期日超過 or 既定期限が重大水準</div>
        </AfCard>
      </div>

      <AfCard pad={0} style={{ overflow: 'hidden' }}>
        <div style={{ display: 'flex', gap: 6, padding: '10px 14px', borderBottom: '1px solid var(--border)', alignItems: 'center', flexWrap: 'wrap' }}>
          {ballFilters.map(f => (
            <button key={f.id} onClick={() => setBall(f.id)} style={{
              height: 26, padding: '0 11px', borderRadius: 'var(--radius-full)', cursor: 'pointer',
              fontSize: 'var(--text-body-sm)', fontWeight: 600, fontFamily: 'var(--font-sans)', display: 'inline-flex', alignItems: 'center', gap: 5,
              border: '1px solid ' + (ball === f.id ? 'var(--brand)' : 'var(--border)'),
              background: ball === f.id ? 'var(--brand-muted)' : 'var(--card)',
              color: ball === f.id ? 'var(--brand)' : 'var(--muted-foreground)',
            }}>{f.label}<span className="mono" style={{ fontSize: 'var(--text-caption)', opacity: 0.8 }}>{f.n}</span></button>
          ))}
          <div style={{ flex: 1 }} />
          <button onClick={() => setOnlyStall(s => !s)} style={{
            height: 26, padding: '0 11px', borderRadius: 'var(--radius-full)', cursor: 'pointer',
            fontSize: 'var(--text-body-sm)', fontWeight: 600, fontFamily: 'var(--font-sans)',
            border: '1px solid ' + (onlyStall ? 'var(--warning)' : 'var(--border)'),
            background: onlyStall ? 'var(--warning-muted)' : 'var(--card)',
            color: onlyStall ? 'var(--warning)' : 'var(--muted-foreground)',
          }}>滞りのみ</button>
        </div>
        <div>
          {rows.map(t => <TaskRow key={t.id} t={t} onOpen={onOpenCase} />)}
          {rows.length === 0 && <div style={{ padding: 32, textAlign: 'center', color: 'var(--muted-foreground)', fontSize: 'var(--text-body-md)' }}>該当するタスクはありません</div>}
        </div>
      </AfCard>

      <div style={{ marginTop: 12 }}>
        <AfAlert variant="info" title="滞り判定(TODO-7・実計算)">🔴重大＝約束期日(予定日)を超過、または既定期限(due_on)超過が重大水準。
          🟠通常＝既定期限超過(重大水準未満)、または約束期日・既定期限が迫っている、または報告リズム超過（決-24「随時」は対象外）の論理和。
          判定式は store.jsx の todoSeverity に集約（SLA監視・0049・決-20/24と同じしきい値）。</AfAlert>
      </div>
    </div>
  );
}

Object.assign(window, { Tasks });
