// Overview screen — Outreach (3 KPIs) + Lead Progression (6 KPIs) + 12-week trendline.
// Defaults to firm-wide all modules; period defaults to Trailing 12 weeks.

function OverviewScreen({ scope, setScope, period, setPeriod, year, setYear }) {
  const F = window.VAULT_FIRM;
  const { fmtNum, fmtUSD } = window.VaultUtils;
  const { PeriodSelector, periodWeeks, aggregate } = window.VaultPeriod;
  const G = window.VAULT_GOALS;

  const [, force] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => G ? G.onChange(force) : undefined, []);
  const goals = G ? G.load() : null;

  const weeks = periodWeeks(period);
  const empty = weeks.length === 0;
  const { totals, people } = empty
    ? { totals: { lists:0, mailings:0, calls:0, leads:0, confCalls:0, visits:0, offers:0, signedLOIs:0, closedDeals:0, custom:0 }, people: [] }
    : aggregate(scope, weeks);

  // Per-week timeseries for trendline
  const series = useMemo(() => {
    if (empty) return [];
    const wset = new Set(weeks);
    const ids = new Set(people.map(p => p.id));
    const buckets = {};
    weeks.forEach(w => buckets[w] = { week: w, calls: 0, leads: 0 });
    F.ACTIVITY.forEach(a => {
      if (!ids.has(a.personId) || !wset.has(a.week)) return;
      buckets[a.week].calls += a.calls;
      buckets[a.week].leads += a.leads;
    });
    return weeks.map(w => buckets[w]);
  }, [weeks, people, empty]);

  // Compute expected per-metric for the scope across the period
  const expected = useMemo(() => {
    if (!goals || empty) return {};
    const out = {};
    for (const m of G.METRICS) out[m] = G.periodExpected(people, m, weeks.length, goals);
    return out;
  }, [goals, people, weeks.length, empty]);

  const bandFor = (metric) => goals ? G.band(totals[metric], expected[metric]) : "neutral";

  return (
    <div style={{ padding: "20px 28px 60px" }}>
      <div className="row" style={{ justifyContent: "space-between", flexWrap: "wrap", gap: 14, marginBottom: 18 }}>
        <ScopeFilters scope={scope} setScope={setScope}/>
        <window.VaultPeriod.PeriodSelector value={period} onChange={setPeriod} year={year} onYearChange={setYear}/>
      </div>

      {empty && <EmptyState period={period}/>}

      {!empty && <>
        {/* Outreach */}
        <SectionHeader title="Outreach" hint="Top-of-funnel volume · vs goal"/>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14, marginBottom: 26 }}>
          <KPI label="Lists"    value={fmtNum(totals.lists)}    hint={`${(totals.lists/Math.max(1,weeks.length)).toFixed(1)} avg/wk`} sparkline={series.map(s => s.calls)} band={bandFor("lists")}    expected={expected.lists}    actual={totals.lists}/>
          <KPI label="Mailings" value={fmtNum(totals.mailings)} hint="Physical + Electronic" sparkline={series.map(s => s.calls)} band={bandFor("mailings")} expected={expected.mailings} actual={totals.mailings}/>
          <KPI label="Calls"    value={fmtNum(totals.calls)}    hint={`${(totals.calls/Math.max(1,weeks.length)).toFixed(0)} avg/wk`} sparkline={series.map(s => s.calls)} band={bandFor("calls")}    expected={expected.calls}    actual={totals.calls}/>
        </div>

        {/* Lead Progression */}
        <SectionHeader title="Lead Progression" hint="Funnel from leads to closed deals · vs goal"/>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 12, marginBottom: 26 }}>
          <KPI label="Leads"        value={fmtNum(totals.leads)}        band={bandFor("leads")}        expected={expected.leads}        actual={totals.leads}/>
          <KPI label="Conf Calls"   value={fmtNum(totals.confCalls)}    band={bandFor("confCalls")}    expected={expected.confCalls}    actual={totals.confCalls}/>
          <KPI label="Visits"       value={fmtNum(totals.visits)}       band={bandFor("visits")}       expected={expected.visits}       actual={totals.visits}/>
          <KPI label="Offers"       value={fmtNum(totals.offers)}       band={bandFor("offers")}       expected={expected.offers}       actual={totals.offers}/>
          <KPI label="Signed LOIs"  value={fmtNum(totals.signedLOIs)}   band={bandFor("signedLOIs")}   expected={expected.signedLOIs}   actual={totals.signedLOIs}/>
          <KPI label="Closed Deals" value={fmtNum(totals.closedDeals)}  band={bandFor("closedDeals")}  expected={expected.closedDeals}  actual={totals.closedDeals} accent/>
        </div>

        {/* Trendline */}
        <SectionHeader title="12-Week Trend" hint="Calls vs Leads · banded against weekly goal"/>
        <div className="card card-pad">
          <Trendline series={series} weeklyGoals={goals ? {
            calls: G.periodExpected(people, "calls", 1, goals),
            leads: G.periodExpected(people, "leads", 1, goals),
          } : null}/>
        </div>
      </>}
    </div>
  );
}

function SectionHeader({ title, hint }) {
  return (
    <div className="row" style={{ marginBottom: 10, gap: 12 }}>
      <h2 className="display" style={{ margin: 0, fontSize: 20, fontWeight: 400, letterSpacing: "-.01em" }}>{title}</h2>
      {hint && <span className="muted small">{hint}</span>}
    </div>
  );
}

function KPI({ label, value, hint, accent, sparkline, band, expected, actual }) {
  const G = window.VAULT_GOALS;
  const hasGoal = expected != null && expected > 0;
  const valueColor = hasGoal && band && band !== "neutral" ? G.color(band) : (accent ? "var(--accent)" : "var(--ink)");
  const ratio = hasGoal ? actual / expected : null;
  const pct = hasGoal ? Math.round(ratio * 100) : null;
  return (
    <div className="card" style={{
      padding: "14px 16px",
      borderColor: hasGoal && band !== "neutral" ? `color-mix(in oklab, ${G.color(band)} 35%, var(--line))` : undefined,
      background: hasGoal && band !== "neutral" ? G.soft(band) : undefined,
      position: "relative",
    }}>
      <div className="row" style={{ alignItems: "center", gap: 6 }}>
        <div className="micro" style={{ flex: 1 }}>{label}</div>
        {hasGoal && (
          <span className="mono" style={{
            fontSize: 9.5, padding: "1px 5px", borderRadius: 4,
            background: G.color(band), color: "white", fontWeight: 600,
            letterSpacing: ".02em",
          }}>{pct}%</span>
        )}
      </div>
      <div className="display mono" style={{ fontSize: 30, lineHeight: 1.1, color: valueColor, marginTop: 2 }}>{value}</div>
      {hasGoal
        ? <div className="muted small mono" style={{ fontSize: 10.5, marginTop: 2 }}>goal {Math.round(expected).toLocaleString()}</div>
        : (hint && <div className="muted small mono" style={{ fontSize: 10.5, marginTop: 2 }}>{hint}</div>)}
      {sparkline && sparkline.length > 1 && <Sparkline data={sparkline} accent={accent}/>}
    </div>
  );
}

function Sparkline({ data, accent }) {
  if (!data || data.length < 2) return null;
  const w = 200, h = 28;
  const max = Math.max(...data, 1);
  const min = Math.min(...data, 0);
  const span = Math.max(1, max - min);
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * w;
    const y = h - ((v - min) / span) * h;
    return `${x.toFixed(1)},${y.toFixed(1)}`;
  }).join(" ");
  return (
    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ width: "100%", height: 28, marginTop: 8 }}>
      <polyline points={pts} fill="none" stroke={accent ? "var(--accent)" : "var(--muted-2)"} strokeWidth="1.4"/>
    </svg>
  );
}

function Trendline({ series, weeklyGoals }) {
  if (!series.length) return null;
  const G = window.VAULT_GOALS;
  const w = 1200, h = 220, pad = { l: 36, r: 12, t: 16, b: 26 };
  const innerW = w - pad.l - pad.r, innerH = h - pad.t - pad.b;
  const maxC = Math.max(...series.map(s => s.calls), 1);
  const maxL = Math.max(...series.map(s => s.leads), 1);
  const maxY = Math.max(maxC, maxL * 12, weeklyGoals ? weeklyGoals.calls : 0, weeklyGoals ? weeklyGoals.leads * 12 : 0);
  const xAt = (i) => pad.l + (i / Math.max(1, series.length - 1)) * innerW;
  const yAt = (v) => pad.t + innerH - (v / maxY) * innerH;

  const callsPath = series.map((s, i) => `${i === 0 ? "M" : "L"}${xAt(i).toFixed(1)},${yAt(s.calls).toFixed(1)}`).join(" ");
  const callsArea = callsPath + ` L${xAt(series.length-1)},${pad.t+innerH} L${xAt(0)},${pad.t+innerH} Z`;
  const leadsPath = series.map((s, i) => `${i === 0 ? "M" : "L"}${xAt(i).toFixed(1)},${yAt(s.leads * 12).toFixed(1)}`).join(" ");
  const leadsArea = leadsPath + ` L${xAt(series.length-1)},${pad.t+innerH} L${xAt(0)},${pad.t+innerH} Z`;

  return (
    <div>
      <div className="row" style={{ gap: 18, marginBottom: 8 }}>
        <LegendDot color="var(--accent)" label="Calls"/>
        <LegendDot color="var(--ink-2)"  label="Leads (×12 scale)"/>
      </div>
      <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ width: "100%", height: h, display: "block" }}>
        {/* Y gridlines */}
        {[0, 0.25, 0.5, 0.75, 1].map((t, i) => (
          <g key={i}>
            <line x1={pad.l} x2={w-pad.r} y1={pad.t + innerH * (1-t)} y2={pad.t + innerH * (1-t)} stroke="var(--line-2)" strokeWidth="1"/>
            <text x={pad.l - 6} y={pad.t + innerH * (1-t) + 3} fontSize="9.5" fill="var(--muted)" textAnchor="end" fontFamily="var(--f-mono)">{Math.round(maxY * t)}</text>
          </g>
        ))}
        {/* Calls (accent) */}
        <path d={callsArea} fill="var(--accent)" opacity=".10"/>
        <path d={callsPath} fill="none" stroke="var(--accent)" strokeWidth="2"/>
        {/* Leads (ink-2) */}
        <path d={leadsArea} fill="var(--ink-2)" opacity=".06"/>
        <path d={leadsPath} fill="none" stroke="var(--ink-2)" strokeWidth="1.6" strokeDasharray="3 3"/>
        {/* Goal lines */}
        {weeklyGoals && weeklyGoals.calls > 0 && (
          <g>
            <line x1={pad.l} x2={w-pad.r} y1={yAt(weeklyGoals.calls)} y2={yAt(weeklyGoals.calls)} stroke="var(--accent)" strokeWidth="1" strokeDasharray="2 4" opacity=".55"/>
            <text x={w-pad.r-4} y={yAt(weeklyGoals.calls)-3} fontSize="9.5" fill="var(--accent)" textAnchor="end" fontFamily="var(--f-mono)">calls goal</text>
          </g>
        )}
        {/* Per-week points colored by band */}
        {weeklyGoals && weeklyGoals.calls > 0 && series.map((s, i) => (
          <circle key={"c"+i} cx={xAt(i)} cy={yAt(s.calls)} r="3" fill={G.color(G.band(s.calls, weeklyGoals.calls))} stroke="var(--surface)" strokeWidth="1"/>
        ))}
        {/* X labels */}
        {series.map((s, i) => (
          (i % 2 === 0) && <text key={i} x={xAt(i)} y={h-8} fontSize="9.5" fill="var(--muted)" textAnchor="middle" fontFamily="var(--f-mono)">{s.week.slice(5)}</text>
        ))}
      </svg>
    </div>
  );
}

function LegendDot({ color, label }) {
  return (
    <span className="row" style={{ gap: 6, fontSize: 11.5, color: "var(--muted)" }}>
      <span style={{ width: 10, height: 10, borderRadius: 2, background: color }}/>
      {label}
    </span>
  );
}

function EmptyState({ period }) {
  return (
    <div className="card card-pad" style={{ textAlign: "center", padding: "60px 20px" }}>
      <div className="display" style={{ fontSize: 28, color: "var(--muted)" }}>No data yet</div>
      <p className="muted" style={{ marginTop: 6 }}>The selected period <span className="mono">{period.toUpperCase()}</span> has no recorded activity.</p>
    </div>
  );
}

window.OverviewScreen = OverviewScreen;
