// Pre-release defects · Risk Hotspots card.
// Purpose: surface *who* is accumulating defects (and the bad patterns behind
// them) so an EM/PM can act on the right culprit — while keeping evidence.
//
// Section order (people → where → evidence):
//   1. Header — total + window filter
//   2. People — developers ranked by defect count, with bad-pattern tags
//   3. Hot modules — slim strip showing where defects concentrate
//   4. Recent evidence — condensed ticket rows (max 4)

const HD_TEAM_OF_MODULE = {
  payments: 'Payments Core',
  webhooks: 'Payments Core',
  idempotency: 'Payments Core',
  auth: 'Auth & Identity',
  disputes: 'Disputes & Risk',
  refunds: 'Disputes & Risk',
  tests: null,
};
const HD_TEAM_COLOR = {
  'Payments Core': 'var(--accent)',
  'Auth & Identity': 'var(--good)',
  'Disputes & Risk': 'var(--warn)',
  'Unassigned': 'var(--text-3)',
};
const hdModuleOf = (p) => (p || '').split('/')[0] || 'other';

function HighDefectsWidget({ openSidePanel, navigate }) {
  const [weeks, setWeeks] = useWindowPref('highDefects.weeks', DATA.DEFAULT_WEEKS);

  // Pre-release only — post-deploy `production` rows are excluded.
  const rows = useMemo(
    () => DATA.defectsInWindow(weeks).filter(r => r.phase === 'pre'),
    [weeks]
  );

  const total = rows.length;
  const titleTone = total >= 5 ? 'bad' : total >= 2 ? 'warn' : 'good';

  // Aggregate signals: per author, per file, per module.
  const agg = useMemo(() => {
    const byAuthor = new Map();   // id → { count, stages }
    const byFile = new Map();     // path → count
    const byModule = new Map();   // module → { count, files }
    for (const r of rows) {
      const a = r.ticket.assignee;
      const aRec = byAuthor.get(a) || { count: 0, stages: { review: 0, qa: 0, staging: 0 } };
      aRec.count++;
      if (r.caughtAt in aRec.stages) aRec.stages[r.caughtAt]++;
      byAuthor.set(a, aRec);

      const seenFiles = new Set();
      (r.ticket.commits || []).forEach(c => (c.files || []).forEach(f => seenFiles.add(f)));
      const seenModules = new Set();
      for (const f of seenFiles) {
        byFile.set(f, (byFile.get(f) || 0) + 1);
        seenModules.add(hdModuleOf(f));
      }
      for (const m of seenModules) {
        const mRec = byModule.get(m) || { count: 0, files: new Map() };
        mRec.count++;
        byModule.set(m, mRec);
      }
      // Track per-module file frequencies (use seenFiles, not multiplied by module count).
      for (const f of seenFiles) {
        const m = hdModuleOf(f);
        const mRec = byModule.get(m);
        if (!mRec) continue;
        mRec.files.set(f, (mRec.files.get(f) || 0) + 1);
      }
    }
    return { byAuthor, byFile, byModule };
  }, [rows]);

  // Top developers (max 4) — who is accumulating the most defects.
  const devRows = useMemo(() => {
    const arr = [...agg.byAuthor.entries()].map(([id, v]) => ({ id, ...v }));
    arr.sort((a, b) => b.count - a.count);
    const maxCount = arr[0]?.count || 1;
    return arr.slice(0, 4).map(r => ({ ...r, pct: Math.round((r.count / maxCount) * 100) }));
  }, [agg.byAuthor]);

  // Top modules (max 4).
  const moduleRows = useMemo(() => {
    const arr = [...agg.byModule.entries()].map(([mod, v]) => {
      const topFileEntry = [...v.files.entries()].sort((a, b) => b[1] - a[1])[0];
      return {
        module: mod,
        count: v.count,
        topFile: topFileEntry ? topFileEntry[0] : null,
        topFileCount: topFileEntry ? topFileEntry[1] : 0,
        team: HD_TEAM_OF_MODULE[mod] || 'Unassigned',
      };
    });
    arr.sort((a, b) => b.count - a.count);
    const maxCount = arr[0]?.count || 1;
    return arr.slice(0, 4).map(r => ({ ...r, pct: Math.round((r.count / maxCount) * 100) }));
  }, [agg.byModule]);

  const listRows = rows.slice(0, 4);
  const filenameOnly = (p) => p.split('/').slice(-1)[0];

  const stageBadge = {
    review:  { label: 'Review',  tone: 'good' },
    qa:      { label: 'QA',      tone: 'accent' },
    staging: { label: 'Staging', tone: 'warn' },
  };

  // ─── Subcomponents (kept local — small, single-use) ────────────────
  const SectionLabel = ({ text, right }) => (
    <div style={{
      padding: '12px 16px 8px',
      display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
    }}>
      <span className="mono-caps" style={{ fontSize: 10, color: 'var(--text-3)', letterSpacing: '0.08em' }}>
        {text}
      </span>
      {right && <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-3)' }}>{right}</span>}
    </div>
  );

  return (
    <div className="card">
      <div className="card-head">
        <div>
          <div className="ch-eyebrow">Defects · last {weeks * 7}d</div>
          <div className="ch-title" style={{ marginTop: 4 }}>
            <Icon name="shield" size={13} style={{ color: 'var(--' + titleTone + ')' }} />
            <span>{total} caught in development cycle</span>
          </div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span className="mono" style={{ color: 'var(--text-3)', fontSize: 11 }}>
            Who & where to focus
          </span>
          <WindowSizeChip value={weeks} onChange={setWeeks} options={[2, 4, 8, 12]} />
        </div>
      </div>

      {/* ─── Empty state ───────────────────────────────────────────────── */}
      {total === 0 && (
        <div style={{ borderTop: '1px solid var(--border)', padding: '14px 16px', color: 'var(--text-3)', fontSize: 12.5 }}>
          No defects observed in this window · clean run
        </div>
      )}

      {/* ─── People · who is accumulating defects ──────────────────────── */}
      {total > 0 && (
        <div style={{ borderTop: '1px solid var(--border)', padding: '12px 16px 14px' }}>
          <div className="mono-caps" style={{ fontSize: 10, color: 'var(--text-3)', letterSpacing: '0.08em', marginBottom: 10 }}>
            Developers · most defects
          </div>
          <div style={{ display: 'grid', gap: 10 }}>
            {devRows.map(d => {
              const dev = DATA.devById(d.id);
              if (!dev) return null;
              return (
                <div
                  key={d.id}
                  className="clickable"
                  onClick={() => navigate('#/profile/' + d.id)}
                  style={{ cursor: 'pointer', display: 'grid', gridTemplateColumns: '24px minmax(0,1fr) auto', gap: 10, alignItems: 'center' }}
                  title={`${dev.name} · ${d.count} defect${d.count === 1 ? '' : 's'}`}
                >
                  <Avatar initials={dev.initials} size={22} />
                  <div style={{ minWidth: 0 }}>
                    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 6 }}>
                      <span style={{ fontSize: 12.5, color: 'var(--text)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                        {dev.name}
                      </span>
                      <span className="mono" style={{ fontSize: 11.5, color: 'var(--text-2)', flex: '0 0 auto' }}>{d.count}</span>
                    </div>
                    <div style={{ height: 4, background: 'var(--surface-3)', borderRadius: 2, marginTop: 5, overflow: 'hidden' }}>
                      <div style={{ width: d.pct + '%', height: '100%', background: d.stages.staging > 0 ? 'var(--bad)' : d.count >= 2 ? 'var(--warn)' : 'var(--accent)' }} />
                    </div>
                  </div>
                  <Icon name="chevron-right" size={12} style={{ color: 'var(--text-3)' }} />
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* ─── Hot modules strip · where ─────────────────────────────────── */}
      {moduleRows.length > 0 && (
        <div style={{ borderTop: '1px solid var(--border)', padding: '10px 16px 12px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
            <span className="mono-caps" style={{ fontSize: 10, color: 'var(--text-3)', letterSpacing: '0.08em', flex: '0 0 auto' }}>
              Hot modules
            </span>
            {moduleRows.map(m => {
              const color = HD_TEAM_COLOR[m.team] || 'var(--accent)';
              return (
                <span
                  key={m.module}
                  className="tag mono"
                  style={{ display: 'inline-flex', alignItems: 'center', gap: 5, color, borderColor: 'var(--border)', background: 'var(--surface-3)' }}
                  title={`${m.module}/ · ${m.count} defect${m.count === 1 ? '' : 's'} · ${m.team}${m.topFile ? ' · top: ' + filenameOnly(m.topFile) : ''}`}
                >
                  <Icon name="flame" size={10} />
                  <span style={{ color: 'var(--text-2)' }}>{m.module}/</span>
                  <span style={{ color }}>·</span>
                  <span>×{m.count}</span>
                </span>
              );
            })}
          </div>
        </div>
      )}

      {/* ─── Recent evidence ────────────────────────────────────────────── */}
      {total > 0 && (
        <div style={{ borderTop: '1px solid var(--border)' }}>
          <SectionLabel
            text="Recent evidence"
            right={`${Math.min(4, listRows.length)} of ${total} · click to open ticket`}
          />
          {listRows.map(r => {
            const t = r.ticket;
            const dev = DATA.devById(t.assignee);
            const daysAgo = Math.max(0, -r.bugSegment.endDay);
            const repeat = (agg.byAuthor.get(t.assignee)?.count || 0) >= 2;
            const ticketFiles = new Set();
            (t.commits || []).forEach(c => (c.files || []).forEach(f => ticketFiles.add(f)));
            const matchedFile = Array.from(ticketFiles).find(f => (agg.byFile.get(f) || 0) >= 2);

            const chips = [];
            if (r.fastMerge) chips.push({ key: 'fm', tone: 'bad', icon: 'zap', label: 'Fast merge' });
            if (r.aiHeavy) chips.push({ key: 'ai', tone: 'warn', icon: 'bot', label: `AI ${r.avgAi}%` });
            if (repeat) chips.push({ key: 're', tone: 'warn', icon: 'user', label: 'Repeat' });
            if (matchedFile) chips.push({ key: 'hf', tone: 'accent', icon: 'flame', label: filenameOnly(matchedFile) });

            const badge = stageBadge[r.caughtAt] || stageBadge.qa;

            return (
              <div
                key={t.id}
                className="clickable"
                onClick={() => navigate('#/ticket/' + t.id)}
                style={{
                  display: 'grid',
                  gridTemplateColumns: 'minmax(0, 1fr) auto',
                  gap: 10,
                  padding: '6px 16px',
                  cursor: 'pointer',
                  borderTop: '1px solid var(--border)',
                }}
              >
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
                  <span
                    className={`tag mono tone-${badge.tone}`}
                    style={{ flex: '0 0 auto', minWidth: 58, justifyContent: 'center', display: 'inline-flex' }}
                    title={`Caught in ${badge.label}`}
                  >
                    {badge.label}
                  </span>
                  <span className="mono" style={{ color: 'var(--text-3)', fontSize: 11.5, flex: '0 0 auto' }}>{t.id}</span>
                  <span style={{
                    fontSize: 12.5, color: 'var(--text)',
                    whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0,
                  }} title={t.title}>
                    {t.title}
                  </span>
                </div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
                  {chips.slice(0, 3).map(c => (
                    <span key={c.key} className={`tag mono tone-${c.tone}`} style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                      <Icon name={c.icon} size={10} />
                      <span>{c.label}</span>
                    </span>
                  ))}
                  {dev && <Avatar initials={dev.initials} size={20} />}
                  <span className="mono" style={{ fontSize: 11, color: 'var(--text-3)', minWidth: 44, textAlign: 'right' }}>
                    {daysAgo === 0 ? 'today' : daysAgo + 'd ago'}
                  </span>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

window.HighDefectsWidget = HighDefectsWidget;
