// Overview dashboard — KPIs and high-level charts
function dealInRange(deal, range, cf, ct) {
  const d = deal.created;
  if (!d || range === 'all') return range === 'all' ? true : true;
  if (range === 'custom') {
    if (cf && d < cf) return false;
    if (ct && d > ct) return false;
    return true;
  }
  const starts = { month: '2026-05-01', quarter: '2026-04-01', fy: '2025-07-01', '12m': '2025-05-27' };
  return d >= (starts[range] || '0000-01-01');
}

function Overview({ deals: dealsProp, stages, reps, months, openDeal, filters, setFilters }) {
  const [dateRange, setDateRange] = React.useState('all');
  const [customFrom, setCustomFrom] = React.useState('');
  const [customTo, setCustomTo] = React.useState('');
  const deals = React.useMemo(
    () => dealsProp.filter((d) => dealInRange(d, dateRange, customFrom, customTo)),
    [dealsProp, dateRange, customFrom, customTo]
  );
  const [stageMode, setStageMode] = React.useState('value'); // 'value' | 'count'
  const active = deals.filter((d) => d.stage !== 'sold' && d.stage !== 'lost');
  const won = deals.filter((d) => d.stage === 'sold');
  const lost = deals.filter((d) => d.stage === 'lost');
  const closed = won.length + lost.length;

  // Totals
  const pipelineTotal = active.reduce((s, d) => s + d.value, 0);
  const wonTotal = won.reduce((s, d) => s + d.value, 0);
  const avgDeal = won.length ? wonTotal / won.length : 0;
  const winRate = closed ? won.length / closed : 0;

  // Pipeline by stage
  const byStage = stages.filter((s) => s.id !== 'sold' && s.id !== 'lost').map((s) => {
    const ds = active.filter((d) => d.stage === s.id);
    return {
      ...s,
      count: ds.length,
      value: ds.reduce((sm, d) => sm + d.value, 0)
    };
  });
  const maxStageVal = Math.max(...byStage.map((b) => b.value), 1);

  // Funnel
  const funnel = stages.filter((s) => s.id !== 'lost').map((s) => {
    const cnt = s.id === 'won' ? won.length : deals.filter((d) => d.stage === s.id).length + won.length + (stages.findIndex((x) => x.id === s.id) < stages.findIndex((x) => x.id === 'won') ? 0 : 0);
    return { ...s, count: cnt };
  });
  // Simpler: funnel cumulative — each stage = remaining deals that reached at least that point
  const stageOrder = ['possible', 'in_progress', 'sold'];
  const funnelData = stageOrder.map((sid, i) => {
    // Count deals currently at this stage or beyond (in active OR won)
    const reached = deals.filter((d) => {
      if (d.stage === 'lost') return false;
      const dIdx = stageOrder.indexOf(d.stage);
      return dIdx >= i;
    }).length;
    return { id: sid, label: stages.find((s) => s.id === sid).label, count: reached };
  });
  const maxFunnel = funnelData[0].count;

  // Trend (won $ by month) — derived from the deals currently in scope so it reacts to filters
  const maxMonth = Math.max(...months.map((m) => m.won), 1);
  const trendMonths = React.useMemo(() => {
    const labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    const end = new Date('2026-05-01'); // dataset's current month
    const series = [];
    const idx = {};
    for (let i = 5; i >= 0; i--) {
      const dt = new Date(end.getFullYear(), end.getMonth() - i, 1);
      const key = `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}`;
      idx[key] = series.length;
      series.push({ key, month: labels[dt.getMonth()], won: 0, lost: 0 });
    }
    deals.forEach((d) => {
      const closeDate = d.forecastDepositMonth || d.lastActivity || d.created;
      if (!closeDate) return;
      const key = closeDate.slice(0, 7);
      if (idx[key] == null) return;
      if (d.stage === 'sold') series[idx[key]].won += d.value || 0;else
      if (d.stage === 'lost') series[idx[key]].lost += d.value || 0;
    });
    return series;
  }, [deals]);

  // Top reps (by won $ this period)
  const repAgg = reps.map((r) => {
    const repWon = won.filter((d) => d.rep === r.id);
    const repActive = active.filter((d) => d.rep === r.id);
    return {
      ...r,
      wonVal: repWon.reduce((s, d) => s + d.value, 0),
      wonCount: repWon.length,
      activeVal: repActive.reduce((s, d) => s + d.value, 0)
    };
  }).sort((a, b) => b.wonVal - a.wonVal);
  const maxRep = Math.max(...repAgg.map((r) => r.wonVal), 1);

  // Aging summary
  const stuck = active.filter((d) => d.lastActivityDaysAgo > 21);
  const veryStuck = active.filter((d) => d.lastActivityDaysAgo > 30);

  // Recent activity (most recent across all deals)
  const recentDeals = [...deals].
  sort((a, b) => a.lastActivityDaysAgo - b.lastActivityDaysAgo).
  slice(0, 6);

  // ===== Customizable widgets =====
  const WIDGETS = [
  { id: 'kpis', label: 'KPI summary cards' },
  { id: 'stage', label: 'Pipeline by stage' },
  { id: 'funnel', label: 'Conversion funnel' },
  { id: 'donut', label: 'Status breakdown (pie)' },
  { id: 'waterfall', label: 'Pipeline → sold waterfall' },
  { id: 'trend', label: 'Closed-won trend' },
  { id: 'reps', label: 'Top performers' },
  { id: 'attention', label: 'Needs attention' },
  { id: 'activity', label: 'Latest activity' }];

  const [vis, setVis] = React.useState(() => {
    try {
      const s = localStorage.getItem('pearler_overview_widgets_v1');
      if (s) return JSON.parse(s);
    } catch (e) {}
    return {};
  });
  const [customizing, setCustomizing] = React.useState(false);
  const show = (id) => vis[id] !== false;
  const toggle = (id) => setVis((prev) => {
    const next = { ...prev, [id]: prev[id] === false ? true : false };
    try {localStorage.setItem('pearler_overview_widgets_v1', JSON.stringify(next));} catch (e) {}
    return next;
  });

  // Donut: all deals by status
  const donutSegs = stages.map((s) => {
    const ds = deals.filter((d) => d.stage === s.id);
    return { label: s.label, value: ds.length, display: ds.length, color: `var(--s-${s.id})` };
  }).filter((s) => s.value > 0);

  // Waterfall: Total quoted → −Lost → −Still open → = Sold (reconciles exactly)
  const allVal = deals.reduce((s, d) => s + d.value, 0);
  const lostVal = lost.reduce((s, d) => s + d.value, 0);
  const waterfallSteps = [
  { label: 'Total quoted', value: allVal, type: 'start' },
  { label: 'Lost', value: lostVal, type: 'subtract' },
  { label: 'Still open', value: pipelineTotal, type: 'subtract' },
  { label: 'Sold', value: wonTotal, type: 'total' }];


  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, gap: 10, flexWrap: 'wrap' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 12, color: 'var(--ink-3)' }}>Date range</span>
          <select className="sel" value={dateRange} onChange={(e) => setDateRange(e.target.value)}>
            <option value="all">All time</option>
            <option value="month">This month</option>
            <option value="quarter">This quarter</option>
            <option value="fy">This financial year</option>
            <option value="12m">Last 12 months</option>
            <option value="custom">Custom range…</option>
          </select>
          {dateRange === 'custom' &&
          <>
              <input type="date" className="sel" value={customFrom} onChange={(e) => setCustomFrom(e.target.value)} style={{ padding: '5px 8px' }} />
              <span style={{ fontSize: 12, color: 'var(--ink-3)' }}>to</span>
              <input type="date" className="sel" value={customTo} onChange={(e) => setCustomTo(e.target.value)} style={{ padding: '5px 8px' }} />
            </>
          }
          <span style={{ fontSize: 11.5, color: 'var(--ink-4)' }} className="num">{deals.length} deals</span>
        </div>
        <button className="btn sm" onClick={() => setCustomizing((c) => !c)}>
          <Icon name="sliders" size={12} /> Customise dashboard
        </button>
      </div>
      {customizing &&
      <div className="card" style={{ marginBottom: 16, padding: '14px 18px' }}>
          <div style={{ fontSize: 12.5, fontWeight: 600, marginBottom: 4 }}>Show or hide dashboard widgets</div>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginBottom: 12 }}>Your layout is saved on this device. Each user can arrange their own.</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 }}>
            {WIDGETS.map((w) =>
          <label key={w.id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12.5, cursor: 'pointer', padding: '6px 10px', border: '1px solid var(--border)', borderRadius: 6, background: show(w.id) ? 'var(--accent-soft)' : 'var(--surface)' }}>
                <input type="checkbox" checked={show(w.id)} onChange={() => toggle(w.id)} style={{ margin: 0 }} />
                {w.label}
              </label>
          )}
          </div>
        </div>
      }

      {show('kpis') && <div className="grid-kpis" style={{ textAlign: "justify" }}>
        <Kpi
          label="Pipeline value"
          value={fmt.money(pipelineTotal, true)}
          deltaPct={0.124}
          foot={`${active.length} active deals`} />
        
        <Kpi
          label="Closed-won (period)"
          value={fmt.money(wonTotal, true)}
          deltaPct={0.087}
          foot={`${won.length} wins · ${fmt.money(avgDeal, true)} avg`} />
        
        <Kpi
          label="Win rate"
          value={fmt.pct(winRate, 1)}
          deltaPct={-0.032}
          foot={`${won.length} won / ${closed} closed`} />
        
        <Kpi
          label="Stuck (>21d no activity)"
          value={stuck.length}
          deltaPct={0.045}
          deltaInvert
          foot={`${veryStuck.length} critical (>30d)`}
          alert />
        
      </div>}

      {(show('stage') || show('funnel')) && <div className="grid-2">
        {show('stage') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Pipeline by stage</div>
              <div className="card-sub">Active deal {stageMode}, current snapshot</div>
            </div>
            <div className="seg">
              <button className={stageMode === 'value' ? 'on' : ''} onClick={() => setStageMode('value')}>Value</button>
              <button className={stageMode === 'count' ? 'on' : ''} onClick={() => setStageMode('count')}>Count</button>
            </div>
          </div>
          <div className="card-pad">
            {byStage.map((s) => {
              const metric = stageMode === 'value' ? s.value : s.count;
              const maxMetric = stageMode === 'value' ? maxStageVal : Math.max(...byStage.map((b) => b.count), 1);
              const display = stageMode === 'value' ? fmt.money(metric, true) : metric;
              return (
                <div className="chart-row" key={s.id}>
                  <div className="lbl">
                    <span className="dot" style={{ width: 8, height: 8, borderRadius: 4, background: `var(--s-${s.id})`, display: 'inline-block' }}></span>
                    {s.label}
                  </div>
                  <div className="bar-wrap">
                    <div
                      className={`bar ${s.id}`}
                      style={{ width: metric / maxMetric * 100 + '%' }}>
                      
                      {metric / maxMetric > 0.18 && <span>{display}</span>}
                    </div>
                  </div>
                  <div className="val">
                    {stageMode === 'value' ?
                    <><span className="num">{s.count}</span> deals</> :
                    <span className="num">{fmt.money(s.value, true)}</span>
                    }
                  </div>
                </div>);

            })}
          </div>
        </div>}

        {show('funnel') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Conversion funnel</div>
              <div className="card-sub">Deals that reached each stage</div>
            </div>
          </div>
          <div className="card-pad">
            <div className="funnel">
              {funnelData.map((f, i) => {
                const w = f.count / maxFunnel * 100;
                const conv = i === 0 ? null : f.count / funnelData[i - 1].count;
                return (
                  <div className="funnel-row" key={f.id}>
                    <div className="lbl">{f.label}</div>
                    <div className="funnel-bar-wrap">
                      <div className="funnel-bar" style={{ width: Math.max(w, 22) + '%', background: f.id === 'sold' ? 'var(--won)' : `var(--s-${f.id})` }}>
                        <span className="num">{f.count}</span>
                        {i > 0 && <span style={{ opacity: 0.8, fontSize: 11 }}>{fmt.pct(conv, 0)}</span>}
                      </div>
                    </div>
                    <div className="conv">
                      {i === 0 ? 'Start' : `${fmt.pct(funnelData[i].count / funnelData[0].count, 0)} kept`}
                    </div>
                  </div>);

              })}
            </div>
          </div>
        </div>}
      </div>}

      {(show('donut') || show('waterfall')) && <div className="grid-2-eq">
        {show('donut') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Status breakdown</div>
              <div className="card-sub">All deals by current status</div>
            </div>
          </div>
          <div className="card-pad">
            <DonutChart segments={donutSegs} centerLabel={deals.length} centerSub="deals" />
          </div>
        </div>}

        {show('waterfall') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Pipeline → sold</div>
              <div className="card-sub">How total quoted value resolves</div>
            </div>
          </div>
          <div className="card-pad">
            <WaterfallChart steps={waterfallSteps} fmtVal={(v) => fmt.money(v, true)} />
          </div>
        </div>}
      </div>}

      {(show('trend') || show('reps')) && <div className="grid-2">
        {show('trend') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Closed-won trend</div>
              <div className="card-sub">Last 6 months, AUD</div>
            </div>
            <span className="pill info"><span className="dot"></span>vs same period last year +14.2%</span>
          </div>
          <div className="card-pad">
            <TrendChart months={trendMonths} />
          </div>
        </div>}

        {show('reps') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Top reps (closed-won)</div>
              <div className="card-sub">By value, current period</div>
            </div>
          </div>
          <div className="card-pad">
            {repAgg.slice(0, 6).map((r) =>
            <div className="chart-row" key={r.id} style={{ gridTemplateColumns: '160px 1fr 90px' }}>
                <div className="lbl">
                  <Avatar name={r.name} sz="sm" />
                  <span style={{ fontSize: 12.5 }}>{r.name}</span>
                </div>
                <div className="bar-wrap">
                  <div className="bar accent" style={{ width: r.wonVal / maxRep * 100 + '%' }}>
                    {r.wonVal / maxRep > 0.25 && <span>{fmt.money(r.wonVal, true)}</span>}
                  </div>
                </div>
                <div className="val">
                  <span className="num">{r.wonCount}</span> wins
                </div>
              </div>
            )}
          </div>
        </div>}
      </div>}

      {(show('attention') || show('activity')) && <div className="grid-2">
        {show('attention') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Needs attention</div>
              <div className="card-sub">High-value or stuck deals</div>
            </div>
            <button className="btn sm" onClick={() => setFilters({ ...filters, agingOnly: true })}>
              View all <Icon name="arrow-right" size={11} />
            </button>
          </div>
          <div className="tbl-wrap">
            <table className="tbl">
              <thead>
                <tr>
                  <th>Deal</th>
                  <th>Stage</th>
                  <th className="num-col">Value</th>
                  <th className="num-col">Idle</th>
                </tr>
              </thead>
              <tbody>
                {stuck.sort((a, b) => b.value - a.value).slice(0, 6).map((d, i) =>
                <tr key={d.id + '-stuck-' + i} onClick={() => openDeal(d)}>
                    <td>
                      <div className="customer-cell">
                        <Avatar name={d.customer} sz="sm" />
                        <div className="customer-meta">
                          <div className="customer-name">{d.customer}</div>
                          <div className="customer-sub">{d.product}</div>
                        </div>
                      </div>
                    </td>
                    <td><StagePill stage={d.stage} stages={stages} /></td>
                    <td className="num-col"><span className="num">{fmt.money(d.value, true)}</span></td>
                    <td className={`num-col age-cell ${ageBucket(d.lastActivityDaysAgo)}`}>
                      <span className="num">{d.lastActivityDaysAgo}d</span>
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </div>}

        {show('activity') && <div className="card">
          <div className="card-hd">
            <div>
              <div className="card-title">Latest activity</div>
              <div className="card-sub">Most recent customer touches</div>
            </div>
          </div>
          <div className="card-pad" style={{ paddingTop: 6, paddingBottom: 6 }}>
            <div className="activity-list">
              {recentDeals.map((d, i) => {
                const a = d.activities[0] || { type: 'note', label: 'Note', daysAgo: d.lastActivityDaysAgo };
                return (
                  <div className="activity-item" key={d.id + '-recent-' + i} style={{ padding: '8px 0', borderBottom: '1px solid var(--border)', cursor: 'pointer' }} onClick={() => openDeal(d)}>
                    <span className={`activity-dot ${a.type}`}></span>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 12.5 }}>
                        <span style={{ fontWeight: 500 }}>{d.repName.split(' ')[0]}</span>{' '}
                        <span style={{ color: 'var(--ink-3)' }}>{a.label.toLowerCase()} with</span>{' '}
                        <span style={{ fontWeight: 500 }}>{d.customer}</span>
                      </div>
                      <div className="activity-meta">
                        {d.product} · {fmt.money(d.value, true)} · <StagePill stage={d.stage} stages={stages} />
                      </div>
                    </div>
                    <div className="activity-meta" style={{ whiteSpace: 'nowrap' }}>{fmt.daysAgo(a.daysAgo)}</div>
                  </div>);

              })}
            </div>
          </div>
        </div>}
      </div>}
    </div>);

}

function Kpi({ label, value, deltaPct, deltaInvert, foot, alert }) {
  const dir = deltaPct > 0.005 ? 'up' : deltaPct < -0.005 ? 'down' : 'flat';
  let cls = dir;
  if (deltaInvert) cls = dir === 'up' ? 'down' : dir === 'down' ? 'up' : 'flat';
  const sign = deltaPct > 0 ? '+' : '';
  const pctAbs = Math.abs(deltaPct * 100).toFixed(1);
  const deltaText = deltaPct < 0 ? `(${pctAbs}%)` : `${sign}${pctAbs}%`;
  return (
    <div className="kpi" style={{ width: "550px" }}>
      <div className="kpi-label">{label}</div>
      <div className="kpi-value num" style={{ textAlign: "justify" }}>{value}</div>
      <div className="kpi-meta">
        <span className={`delta ${cls}`}>
          <Icon name={dir === 'up' ? 'arrow-up' : dir === 'down' ? 'arrow-down' : 'arrow-right'} size={11} />
          {deltaText}
        </span>
        <span className="kpi-foot">{foot}</span>
      </div>
    </div>);

}

function TrendChart({ months }) {
  const W = 600,H = 200,P = { l: 40, r: 36, t: 12, b: 26 };
  if (!months || months.length === 0) {
    return (
      <div style={{ height: 200, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-3)', fontSize: 13 }}>
        No trend data yet — closed deals will appear here.
      </div>
    );
  }
  const max = Math.max(...months.map((m) => m.won), ...months.map((m) => m.lost * 2), 1);
  const x = (i) => months.length === 1 ? (P.l + (W - P.l - P.r) / 2) : (P.l + i / (months.length - 1) * (W - P.l - P.r));
  const y = (v) => P.t + (1 - v / max) * (H - P.t - P.b);

  const wonPath = months.map((m, i) => `${i === 0 ? 'M' : 'L'} ${x(i)} ${y(m.won)}`).join(' ');
  const wonArea = `${wonPath} L ${x(months.length - 1)} ${H - P.b} L ${x(0)} ${H - P.b} Z`;
  const lostPath = months.map((m, i) => `${i === 0 ? 'M' : 'L'} ${x(i)} ${y(m.lost)}`).join(' ');

  const ticks = 4;
  const tickVals = [];
  for (let i = 0; i <= ticks; i++) tickVals.push(max / ticks * i);

  return (
    <svg className="area-chart" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none">
      <defs>
        <linearGradient id="wonGrad" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor="var(--won)" stopOpacity="0.25" />
          <stop offset="100%" stopColor="var(--won)" stopOpacity="0" />
        </linearGradient>
      </defs>
      {tickVals.map((v, i) =>
      <g key={i}>
          <line x1={P.l} x2={W - P.r} y1={y(v)} y2={y(v)} stroke="var(--border)" strokeWidth="1" />
          <text x={P.l - 6} y={y(v) + 3} textAnchor="end" fontSize="9.5" fill="var(--ink-3)" fontFamily="Geist Mono">
            {fmt.money(v, true)}
          </text>
        </g>
      )}
      <path d={wonArea} fill="url(#wonGrad)" />
      <path d={wonPath} fill="none" stroke="var(--won)" strokeWidth="2" />
      <path d={lostPath} fill="none" stroke="var(--lost)" strokeWidth="1.5" strokeDasharray="3 3" opacity="0.7" />
      {months.map((m, i) =>
      <g key={m.month}>
          <circle cx={x(i)} cy={y(m.won)} r="3.5" fill="white" stroke="var(--won)" strokeWidth="2" />
          <text x={x(i)} y={H - 8} textAnchor="middle" fontSize="10" fill="var(--ink-3)" fontFamily="Geist Mono">
            {m.month}
          </text>
        </g>
      )}
      <g transform={`translate(${W - 130}, ${P.t + 4})`}>
        <rect x="0" y="0" width="124" height="36" fill="var(--surface)" stroke="var(--border)" rx="4" />
        <circle cx="10" cy="12" r="3" fill="var(--won)" />
        <text x="18" y="15" fontSize="10" fill="var(--ink-2)">Closed-won</text>
        <line x1="6" x2="14" y1="26" y2="26" stroke="var(--lost)" strokeWidth="1.5" strokeDasharray="2 2" />
        <text x="18" y="29" fontSize="10" fill="var(--ink-2)">Closed-lost</text>
      </g>
    </svg>);

}

window.Overview = Overview;
window.Kpi = Kpi;