// October & Co BI Dashboard — single-file SPA
// Loads data.json, renders 4 tabs: Google Overview, Google Campaigns, Meta Overview, Meta Campaigns

const fmtNum = (n, dec = 0) => {
  if (n === null || n === undefined || isNaN(n)) return '—';
  const x = Number(n);
  if (Math.abs(x) >= 1e7) return (x / 1e7).toFixed(2) + 'Cr';
  if (Math.abs(x) >= 1e5) return (x / 1e5).toFixed(2) + 'L';
  if (Math.abs(x) >= 1e3) return x.toLocaleString('en-IN', { maximumFractionDigits: dec });
  return x.toLocaleString('en-IN', { maximumFractionDigits: dec });
};
const fmtMoney = (n) => '₹' + fmtNum(n, 0);
const fmtPct = (n) => (n == null ? '—' : Number(n).toFixed(2) + '%');
const fmtRoas = (n) => (n == null || !isFinite(n) ? '—' : Number(n).toFixed(2) + 'x');

const RANGES = {
  '7d':   { label: 'Last 7 days',   days: 7 },
  '14d':  { label: 'Last 14 days',  days: 14 },
  '30d':  { label: 'Last 30 days',  days: 30 },
  '60d':  { label: 'Last 60 days',  days: 60 },
  'all':  { label: 'All time',      days: null },
};

function parseISO(s) { const [y,m,d] = s.split('-').map(Number); return new Date(Date.UTC(y, m-1, d)); }
function fmtISO(d) { return d.toISOString().slice(0,10); }
function addDays(d, n) { const x = new Date(d.getTime()); x.setUTCDate(x.getUTCDate()+n); return x; }

function rangeBounds(rangeKey, maxDateStr) {
  const end = parseISO(maxDateStr);
  if (rangeKey === 'all') return { start: null, end };
  const days = RANGES[rangeKey].days;
  return { start: addDays(end, -(days-1)), end };
}

function filterByRange(rows, range, maxDateStr) {
  if (range === 'all') return rows;
  const { start, end } = rangeBounds(range, maxDateStr);
  const s = fmtISO(start), e = fmtISO(end);
  return rows.filter(r => r.date >= s && r.date <= e);
}

function sumGoogle(rows) {
  const o = { spend:0, impressions:0, clicks:0, conversions:0, conv_value:0 };
  for (const r of rows) for (const k of Object.keys(o)) o[k] += +r[k] || 0;
  o.ctr = o.impressions > 0 ? (o.clicks / o.impressions) * 100 : 0;
  o.cpc = o.clicks > 0 ? o.spend / o.clicks : 0;
  o.cpm = o.impressions > 0 ? (o.spend / o.impressions) * 1000 : 0;
  o.cpa = o.conversions > 0 ? o.spend / o.conversions : 0;
  o.roas = o.spend > 0 ? o.conv_value / o.spend : 0;
  return o;
}
function sumMeta(rows) {
  const o = { spend:0, impressions:0, clicks:0, purchases:0, revenue:0 };
  for (const r of rows) for (const k of Object.keys(o)) o[k] += +r[k] || 0;
  o.ctr = o.impressions > 0 ? (o.clicks / o.impressions) * 100 : 0;
  o.cpc = o.clicks > 0 ? o.spend / o.clicks : 0;
  o.cpm = o.impressions > 0 ? (o.spend / o.impressions) * 1000 : 0;
  o.cpa = o.purchases > 0 ? o.spend / o.purchases : 0;
  o.roas = o.spend > 0 ? o.revenue / o.spend : 0;
  return o;
}

// ── Components ─────────────────────────────────────────────────────────────
function Sidebar({ platform, onPlatform }) {
  return (
    <aside className="sb">
      <div className="sb-brand">
        <div className="sb-logo">O</div>
        <div>
          <div className="sb-name">October & Co</div>
          <div className="sb-sub">BI Dashboard</div>
        </div>
      </div>

      <div className="sb-section">Platforms</div>
      <div className={`sb-item ${platform==='google'?'active':''}`} onClick={() => onPlatform('google')}>
        <span className="sb-icon">●</span> Google Ads
      </div>
      <div className={`sb-item ${platform==='meta'?'active':''}`} onClick={() => onPlatform('meta')}>
        <span className="sb-icon">●</span> Meta Ads
      </div>

      <div className="sb-foot">
        Updated: <span id="upd"/>
      </div>
    </aside>
  );
}

function KPI({ label, value, sub }) {
  return (
    <div className="kpi">
      <div className="kpi-label">{label}</div>
      <div className="kpi-val">{value}</div>
      {sub && <div className="kpi-sub">{sub}</div>}
    </div>
  );
}

// Mini line chart — series = [{label, color, data: [n,n,...]}]
function LineChart({ labels, series, height = 240 }) {
  const w = 800, h = height, pl = 50, pr = 20, pt = 16, pb = 30;
  const iw = w - pl - pr, ih = h - pt - pb;
  const n = labels.length;
  if (n === 0) return <div className="empty"><div className="empty-title">No data</div></div>;

  const allVals = series.flatMap(s => s.data);
  const max = Math.max(...allVals, 1);
  const min = 0;

  const x = (i) => pl + (n === 1 ? iw/2 : (i / (n-1)) * iw);
  const y = (v) => pt + ih - ((v - min) / (max - min)) * ih;

  const ticks = 4;
  const gridLines = Array.from({length: ticks+1}, (_, i) => {
    const v = max * (i / ticks);
    return { v, y: y(v) };
  });

  const xLabelEvery = Math.max(1, Math.ceil(n / 8));

  return (
    <svg viewBox={`0 0 ${w} ${h}`} className="chart-wrap">
      {gridLines.map((g, i) => (
        <g key={i}>
          <line x1={pl} x2={pl+iw} y1={g.y} y2={g.y} className="chart-grid"/>
          <text x={pl-8} y={g.y+3} textAnchor="end" className="chart-axis">{fmtNum(g.v, 0)}</text>
        </g>
      ))}
      {labels.map((lab, i) => i % xLabelEvery === 0 && (
        <text key={i} x={x(i)} y={h-10} textAnchor="middle" className="chart-axis">{lab}</text>
      ))}
      {series.map((s, si) => {
        const path = s.data.map((v, i) => `${i===0?'M':'L'} ${x(i)} ${y(v)}`).join(' ');
        const area = path + ` L ${x(n-1)} ${pt+ih} L ${x(0)} ${pt+ih} Z`;
        return (
          <g key={si}>
            <path d={area} className="chart-area" style={{ fill: s.color }}/>
            <path d={path} className="chart-line" style={{ stroke: s.color }}/>
          </g>
        );
      })}
    </svg>
  );
}

// ── Tabs ───────────────────────────────────────────────────────────────────
function GoogleOverview({ data, range }) {
  const rows = filterByRange(data.google.daily, range, data.info.endDate);
  const agg = sumGoogle(rows);
  const labels = rows.map(r => r.date.slice(5));

  return (
    <div className="content">
      <div className="kpi-grid">
        <KPI label="Spend" value={fmtMoney(agg.spend)} sub={`${rows.length} days`}/>
        <KPI label="Impressions" value={fmtNum(agg.impressions)}/>
        <KPI label="Clicks" value={fmtNum(agg.clicks)}/>
        <KPI label="Conversions" value={fmtNum(agg.conversions, 1)}/>
        <KPI label="CTR" value={fmtPct(agg.ctr)}/>
        <KPI label="CPC" value={fmtMoney(agg.cpc)}/>
        <KPI label="CPM" value={fmtMoney(agg.cpm)}/>
        <KPI label="CPA" value={fmtMoney(agg.cpa)}/>
      </div>

      <div className="card">
        <div className="card-h">
          <div className="card-title">Daily spend & conversions</div>
          <div className="card-sub">{rows[0]?.date} → {rows[rows.length-1]?.date}</div>
        </div>
        <LineChart
          labels={labels}
          series={[
            { label: 'Spend', color: 'var(--c1)', data: rows.map(r => r.spend) },
            { label: 'Conv',  color: 'var(--c3)', data: rows.map(r => (r.conversions || 0) * 50) },
          ]}
        />
      </div>

      <div className="card">
        <div className="card-h">
          <div className="card-title">Daily breakdown</div>
          <div className="card-sub">{rows.length} days</div>
        </div>
        <table className="tbl">
          <thead>
            <tr>
              <th>Date</th>
              <th className="num">Spend</th>
              <th className="num">Impr</th>
              <th className="num">Clicks</th>
              <th className="num">CTR</th>
              <th className="num">CPC</th>
              <th className="num">Conv</th>
              <th className="num">CPA</th>
            </tr>
          </thead>
          <tbody>
            {rows.slice().reverse().map(r => (
              <tr key={r.date}>
                <td>{r.date}</td>
                <td className="num">{fmtMoney(r.spend)}</td>
                <td className="num">{fmtNum(r.impressions)}</td>
                <td className="num">{fmtNum(r.clicks)}</td>
                <td className="num">{fmtPct(r.ctr)}</td>
                <td className="num">{fmtMoney(r.cpc)}</td>
                <td className="num">{fmtNum(r.conversions, 1)}</td>
                <td className="num">{fmtMoney(r.conversions > 0 ? r.spend / r.conversions : 0)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function GoogleCampaigns({ data, range }) {
  const rows = filterByRange(data.google.campaigns, range, data.info.endDate);
  // Aggregate per campaign
  const byId = {};
  for (const r of rows) {
    const k = r.campaign_id;
    if (!byId[k]) byId[k] = {
      id: r.campaign_id, name: r.campaign_name, status: r.status, type: r.campaign_type,
      spend:0, impressions:0, clicks:0, conversions:0, conv_value:0,
    };
    const o = byId[k];
    o.spend += +r.spend || 0;
    o.impressions += +r.impressions || 0;
    o.clicks += +r.clicks || 0;
    o.conversions += +r.conversions || 0;
    o.conv_value += +r.conv_value || 0;
  }
  const camps = Object.values(byId).sort((a,b) => b.spend - a.spend);

  return (
    <div className="content">
      <div className="card">
        <div className="card-h">
          <div className="card-title">Campaigns</div>
          <div className="card-sub">{camps.length} campaigns · {rows.length} day-rows</div>
        </div>
        {camps.length === 0 ? (
          <div className="empty"><div className="empty-title">No campaign data in range</div></div>
        ) : (
          <table className="tbl">
            <thead>
              <tr>
                <th>Campaign</th>
                <th>Type</th>
                <th>Status</th>
                <th className="num">Spend</th>
                <th className="num">Impr</th>
                <th className="num">Clicks</th>
                <th className="num">CTR</th>
                <th className="num">CPC</th>
                <th className="num">Conv</th>
                <th className="num">CPA</th>
              </tr>
            </thead>
            <tbody>
              {camps.map(c => {
                const ctr = c.impressions > 0 ? (c.clicks / c.impressions) * 100 : 0;
                const cpc = c.clicks > 0 ? c.spend / c.clicks : 0;
                const cpa = c.conversions > 0 ? c.spend / c.conversions : 0;
                return (
                  <tr key={c.id}>
                    <td>{c.name}</td>
                    <td><span style={{ color: 'var(--ink-3)', fontSize: 11 }}>{c.type}</span></td>
                    <td><span className={`badge ${c.status === 'ENABLED' ? 'enabled' : c.status === 'PAUSED' ? 'paused' : 'removed'}`}>{c.status}</span></td>
                    <td className="num">{fmtMoney(c.spend)}</td>
                    <td className="num">{fmtNum(c.impressions)}</td>
                    <td className="num">{fmtNum(c.clicks)}</td>
                    <td className="num">{fmtPct(ctr)}</td>
                    <td className="num">{fmtMoney(cpc)}</td>
                    <td className="num">{fmtNum(c.conversions, 1)}</td>
                    <td className="num">{fmtMoney(cpa)}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

function MetaOverview({ data, range }) {
  const rows = filterByRange(data.meta.daily || [], range, data.info.endDate);
  if (rows.length === 0) {
    return (
      <div className="content">
        <div className="card">
          <div className="empty">
            <div className="empty-icon">📭</div>
            <div className="empty-title">No Meta data yet</div>
            <div className="empty-sub">
              The Meta API connection for October & Co (act_{data.info.metaAccount}, business 1543862336851257) is not yet wired up.
              <br/><br/>
              Once a working Meta token is configured (via Make.com tool s9088292 or a direct token in the brand registry sheet),
              re-run <code>python3 pull_data.py</code> to populate this tab.
            </div>
          </div>
        </div>
      </div>
    );
  }
  const agg = sumMeta(rows);
  const labels = rows.map(r => r.date.slice(5));
  return (
    <div className="content">
      <div className="kpi-grid">
        <KPI label="Spend" value={fmtMoney(agg.spend)} sub={`${rows.length} days`}/>
        <KPI label="Impressions" value={fmtNum(agg.impressions)}/>
        <KPI label="Clicks" value={fmtNum(agg.clicks)}/>
        <KPI label="Purchases" value={fmtNum(agg.purchases)}/>
        <KPI label="Revenue" value={fmtMoney(agg.revenue)}/>
        <KPI label="ROAS" value={fmtRoas(agg.roas)}/>
        <KPI label="CTR" value={fmtPct(agg.ctr)}/>
        <KPI label="CPC" value={fmtMoney(agg.cpc)}/>
      </div>
      <div className="card">
        <div className="card-h"><div className="card-title">Daily spend & revenue</div></div>
        <LineChart labels={labels} series={[
          { label: 'Spend',   color: 'var(--c2)', data: rows.map(r => r.spend) },
          { label: 'Revenue', color: 'var(--c3)', data: rows.map(r => r.revenue) },
        ]}/>
      </div>
    </div>
  );
}

function MetaCampaigns({ data, range }) {
  const rows = filterByRange(data.meta.campaigns || [], range, data.info.endDate);
  if (rows.length === 0) {
    return (
      <div className="content">
        <div className="card">
          <div className="empty">
            <div className="empty-icon">📭</div>
            <div className="empty-title">No Meta campaign data yet</div>
            <div className="empty-sub">Wire the Meta token then re-run <code>pull_data.py</code>.</div>
          </div>
        </div>
      </div>
    );
  }
  const byId = {};
  for (const r of rows) {
    const k = r.campaign_id;
    if (!byId[k]) byId[k] = { id: r.campaign_id, name: r.campaign_name, objective: r.objective, spend:0, impressions:0, clicks:0, purchases:0, revenue:0 };
    const o = byId[k];
    o.spend += +r.spend || 0; o.impressions += +r.impressions || 0;
    o.clicks += +r.clicks || 0; o.purchases += +r.purchases || 0;
    o.revenue += +r.revenue || 0;
  }
  const camps = Object.values(byId).sort((a,b) => b.spend - a.spend);
  return (
    <div className="content">
      <div className="card">
        <div className="card-h">
          <div className="card-title">Campaigns</div>
          <div className="card-sub">{camps.length} campaigns</div>
        </div>
        <table className="tbl">
          <thead>
            <tr>
              <th>Campaign</th>
              <th>Objective</th>
              <th className="num">Spend</th>
              <th className="num">Impr</th>
              <th className="num">Clicks</th>
              <th className="num">Purch</th>
              <th className="num">Rev</th>
              <th className="num">ROAS</th>
            </tr>
          </thead>
          <tbody>
            {camps.map(c => (
              <tr key={c.id}>
                <td>{c.name}</td>
                <td><span style={{ color: 'var(--ink-3)', fontSize: 11 }}>{c.objective}</span></td>
                <td className="num">{fmtMoney(c.spend)}</td>
                <td className="num">{fmtNum(c.impressions)}</td>
                <td className="num">{fmtNum(c.clicks)}</td>
                <td className="num">{fmtNum(c.purchases)}</td>
                <td className="num">{fmtMoney(c.revenue)}</td>
                <td className="num">{fmtRoas(c.spend > 0 ? c.revenue / c.spend : 0)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ── App ────────────────────────────────────────────────────────────────────
function App({ data }) {
  const [platform, setPlatform] = React.useState('google');
  const [tab, setTab] = React.useState('overview');
  const [range, setRange] = React.useState('30d');

  React.useEffect(() => { setTab('overview'); }, [platform]);

  const Tab =
    platform === 'google'
      ? (tab === 'overview' ? GoogleOverview : GoogleCampaigns)
      : (tab === 'overview' ? MetaOverview : MetaCampaigns);

  const platformLabel = platform === 'google' ? 'Google Ads' : 'Meta Ads';

  return (
    <div className="app">
      <Sidebar platform={platform} onPlatform={setPlatform}/>
      <div className="main">
        <div className="tb">
          <div className="tb-left">
            <div className="tb-title">{platformLabel}</div>
            <span className="tb-crumb">· October & Co</span>
          </div>
          <div className="tb-right">
            <div className="seg">
              {Object.entries(RANGES).map(([k, v]) => (
                <div key={k} className={`seg-item ${range === k ? 'active' : ''}`} onClick={() => setRange(k)}>{v.label}</div>
              ))}
            </div>
          </div>
        </div>

        <div className="tabs">
          <div className={`tab ${tab === 'overview' ? 'active' : ''}`} onClick={() => setTab('overview')}>Overview</div>
          <div className={`tab ${tab === 'campaigns' ? 'active' : ''}`} onClick={() => setTab('campaigns')}>Campaign Performance</div>
        </div>

        <Tab data={data} range={range}/>

        <div style={{ padding: '0 28px 24px', color: 'var(--ink-4)', fontSize: 11 }}>
          Data: {data.info.startDate} → {data.info.endDate} · Updated {new Date(data.info.updated).toLocaleString()} · Currency {data.info.currency}
        </div>
      </div>
    </div>
  );
}

function Boot() {
  const [data, setData] = React.useState(null);
  const [error, setError] = React.useState(null);
  React.useEffect(() => {
    fetch('data.json', { cache: 'no-cache' })
      .then(r => r.json())
      .then(setData)
      .catch(e => setError(String(e)));
  }, []);
  if (error) return <div style={{ padding: 40, color: 'var(--neg)' }}>Failed to load data.json — {error}<br/><br/>Run <code>python3 pull_data.py</code> in the dashboard folder.</div>;
  if (!data) return <div style={{ padding: 40, color: 'var(--ink-3)' }}>Loading October & Co data…</div>;
  return <App data={data}/>;
}

ReactDOM.createRoot(document.getElementById('root')).render(<Boot/>);
