// Actionable insights: panel soiling detection, year-end projection, 7-day solar forecast, 2-period comparison
const { useState, useEffect, useMemo } = React;
const LAT_I = 48.7314, LON_I = 7.8703; // Gambsheim

function clearness(row) { const c = (row.cloud == null ? 50 : row.cloud); return Math.max(0.05, (100 - c) / 100); }

/* ===================== Panel soiling detection ===================== */
function SoilingCheck({ data, refDate }) {
  const result = useMemo(() => {
    if (!data || !data.length) return null;
    const refT = new Date(refDate + 'T00:00:00').getTime();
    const recent = data.filter(r => { const t = new Date(r.date+'T00:00:00').getTime(); return t <= refT && t > refT - 30*86400000; });
    const doy = (d) => { const dt = new Date(d+'T00:00:00'); const start = new Date(Date.UTC(dt.getUTCFullYear(),0,1)); return Math.floor((dt-start)/86400000); };
    const refDoy = doy(refDate);
    const hist = data.filter(r => {
      const rDoy = doy(r.date);
      const diff = Math.min(Math.abs(rDoy - refDoy), 365 - Math.abs(rDoy - refDoy));
      return diff <= 15 && r.date <= refDate && r.date.slice(0,4) !== refDate.slice(0,4);
    });
    if (recent.length < 10 || hist.length < 15) return null;
    const ratioOf = (rows) => {
      const pv = rows.reduce((a,r) => a + (r.pvAuto||0) + (r.pvSold||0), 0);
      const cl = rows.reduce((a,r) => a + clearness(r), 0);
      return cl > 0 ? pv / cl : 0;
    };
    const curRatio = ratioOf(recent);
    const histRatio = ratioOf(hist);
    if (histRatio <= 0) return null;
    const soilingPct = (histRatio - curRatio) / histRatio;
    let status, label, color;
    if (soilingPct > 0.15) { status = 'warn'; label = '🔧 Nettoyage conseillé'; color = 'var(--accent)'; }
    else if (soilingPct > 0.07) { status = 'watch'; label = '👀 À surveiller'; color = 'var(--sun)'; }
    else { status = 'ok'; label = '✅ Panneaux propres'; color = 'var(--green-glow)'; }
    return { soilingPct, status, label, color, curRatio, histRatio };
  }, [data, refDate]);

  if (!result) return null;
  const [open, setOpen] = useState(false);
  return (
    <div className="insight-card" style={{cursor:'pointer'}} onClick={() => setOpen(true)}>
      <div className="insight-head">
        <span className="eyebrow">état des panneaux</span>
        <span style={{color: result.color, fontFamily:'Geist Mono', fontSize:11, letterSpacing:'.04em'}}>{result.label}</span>
      </div>
      <div className="insight-sub">
        Rendement/soleil 30j : <strong>{result.curRatio.toFixed(1)}</strong> vs historique même période : <strong>{result.histRatio.toFixed(1)}</strong>
        {result.soilingPct > 0.07 && <> — écart de <strong>{(result.soilingPct*100).toFixed(0)}%</strong>, hors effet météo/saison</>}
      </div>
      {open && <SoilingHistoryModal data={data} onClose={(e) => { e.stopPropagation(); setOpen(false); }} />}
    </div>
  );
}

function SoilingHistoryModal({ data, onClose }) {
  const [tip, setTip] = useState(null);
  const monthly = useMemo(() => {
    const m = new Map();
    for (const r of data) {
      const key = r.date.slice(0,7);
      if (!m.has(key)) m.set(key, { auto: 0, sold: 0, cl: 0 });
      const e = m.get(key);
      e.auto += r.pvAuto||0;
      e.sold += r.pvSold||0;
      e.cl += clearness(r);
    }
    return [...m.entries()].sort((a,b)=>a[0].localeCompare(b[0]))
      .map(([key, v]) => ({
        key,
        auto: v.cl > 0 ? v.auto / v.cl : 0,
        sold: v.cl > 0 ? v.sold / v.cl : 0,
        total: v.cl > 0 ? (v.auto + v.sold) / v.cl : 0,
      }))
      .filter(d => d.auto > 0 || d.sold > 0);
  }, [data]);

  const [visible, setVisible] = useState({ total: true, auto: true, sold: true, trend: true });
  const toggle = (k) => setVisible(v => ({ ...v, [k]: !v[k] }));

  // Linear regression trend on the total series
  const trendLine = useMemo(() => {
    const n = monthly.length; if (n < 2) return null;
    const xs = monthly.map((_, i) => i);
    const ys = monthly.map(d => d.total);
    const meanX = xs.reduce((a,v)=>a+v,0)/n, meanY = ys.reduce((a,v)=>a+v,0)/n;
    let num = 0, den = 0;
    for (let i = 0; i < n; i++) { num += (xs[i]-meanX)*(ys[i]-meanY); den += (xs[i]-meanX)**2; }
    const slope = den !== 0 ? num/den : 0;
    const intercept = meanY - slope*meanX;
    return monthly.map((_, i) => slope*i + intercept);
  }, [monthly]);

  const W = 640, H = 280, pad = { l: 44, r: 16, t: 14, b: 34 };
  const innerW = W - pad.l - pad.r, innerH = H - pad.t - pad.b;
  const maxV = Math.max(...monthly.map(d => d.total), 1) * 1.1;
  const x = (i) => pad.l + (monthly.length > 1 ? innerW * i / (monthly.length - 1) : innerW/2);
  const y = (v) => pad.t + innerH - (v / maxV) * innerH;
  const pathAuto = monthly.map((d,i) => (i?'L':'M') + x(i) + ' ' + y(d.auto)).join(' ');
  const pathSold = monthly.map((d,i) => (i?'L':'M') + x(i) + ' ' + y(d.sold)).join(' ');
  const pathTotal = monthly.map((d,i) => (i?'L':'M') + x(i) + ' ' + y(d.total)).join(' ');
  const pathTrend = trendLine ? trendLine.map((v,i) => (i?'L':'M') + x(i) + ' ' + y(v)).join(' ') : '';
  const ticks = [0,0.25,0.5,0.75,1].map(p => maxV*p);

  return (
    <div className="kpi-modal-backdrop" onClick={onClose}>
      <div className="kpi-modal" style={{maxWidth:680}} onClick={e => e.stopPropagation()}>
        <div className="kpi-modal-head">
          <div>
            <div className="eyebrow">historique</div>
            <div className="panel-title" style={{fontSize:20}}>Rendement solaire mensuel</div>
          </div>
          <button className="drill-close" onClick={onClose}>Fermer ✕</button>
        </div>
        <div className="insight-sub" style={{marginBottom:6}}>
          kWh produits par unité d'ensoleillement (clarté du ciel). Seule la courbe <strong>totale</strong> (auto-conso + revente) reflète la performance réelle des panneaux — auto-conso et revente séparément dépendent surtout de vos habitudes de consommation, pas de l'état des panneaux.
        </div>
        <div className="legend" style={{marginBottom:8}}>
          <div className="legend-item" style={{cursor:'pointer', opacity: visible.total?1:.35}} onClick={() => toggle('total')}><span className="legend-swatch" style={{background:'var(--ink)', height:2, borderRadius:0}}></span>Total (perf. panneaux)</div>
          <div className="legend-item" style={{cursor:'pointer', opacity: visible.auto?1:.35}} onClick={() => toggle('auto')}><span className="legend-swatch" style={{background:'var(--green)'}}></span>Auto-consommée</div>
          <div className="legend-item" style={{cursor:'pointer', opacity: visible.sold?1:.35}} onClick={() => toggle('sold')}><span className="legend-swatch" style={{background:'var(--accent)'}}></span>Vendue au réseau</div>
          <div className="legend-item" style={{cursor:'pointer', opacity: visible.trend?1:.35}} onClick={() => toggle('trend')}><span className="legend-swatch" style={{background:'var(--sun)', height:2, borderRadius:0}}></span>Tendance</div>
        </div>
        <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} onMouseLeave={() => setTip(null)}>
          {ticks.map((t,i) => (
            <g key={i}>
              <line x1={pad.l} y1={y(t)} x2={W-pad.r} y2={y(t)} stroke="var(--line-soft)" strokeDasharray="2 4" />
              <text x={pad.l-8} y={y(t)+4} fontSize="9" fill="var(--ink-mute)" textAnchor="end" fontFamily="Geist Mono">{t.toFixed(0)}</text>
            </g>
          ))}
          {monthly.map((d,i) => d.key.endsWith('-01') && (
            <g key={'y'+i}>
              <line x1={x(i)} y1={pad.t} x2={x(i)} y2={H-pad.b} stroke="var(--line)" strokeOpacity=".5" strokeDasharray="2 3" />
              <text x={x(i)} y={H-pad.b+16} fontSize="10" fill="var(--ink)" textAnchor="middle" fontFamily="Geist Mono" fontWeight="600">{d.key.slice(0,4)}</text>
            </g>
          ))}
          <path d={pathSold} fill="none" stroke="var(--accent)" strokeWidth="1.5" strokeOpacity=".7" style={{display: visible.sold?'inline':'none'}} />
          <path d={pathAuto} fill="none" stroke="var(--green)" strokeWidth="1.5" strokeOpacity=".7" style={{display: visible.auto?'inline':'none'}} />
          <path d={pathTotal} fill="none" stroke="var(--ink)" strokeWidth="2.5" style={{display: visible.total?'inline':'none'}} />
          {visible.trend && pathTrend && <path d={pathTrend} fill="none" stroke="var(--sun)" strokeWidth="2" strokeDasharray="6 4" />}
          {monthly.map((d,i) => (
            <g key={i}
               onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY, content: <>
                 <div className="tt-date">{d.key}</div>
                 <div className="tt-row"><span><span className="tt-swatch" style={{background:'var(--ink)'}}></span>Total</span><span>{d.total.toFixed(1)}</span></div>
                 <div className="tt-row"><span><span className="tt-swatch" style={{background:'var(--green)'}}></span>Auto-conso.</span><span>{d.auto.toFixed(1)}</span></div>
                 <div className="tt-row"><span><span className="tt-swatch" style={{background:'var(--accent)'}}></span>Vendue</span><span>{d.sold.toFixed(1)}</span></div>
               </>})}
               onMouseLeave={() => setTip(null)}>
              {visible.sold && <circle cx={x(i)} cy={y(d.sold)} r="2" fill="var(--bg-card)" stroke="var(--accent)" strokeWidth="1.2" />}
              {visible.auto && <circle cx={x(i)} cy={y(d.auto)} r="2" fill="var(--bg-card)" stroke="var(--green)" strokeWidth="1.2" />}
              {visible.total && <circle cx={x(i)} cy={y(d.total)} r="2.5" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="1.5" />}
            </g>
          ))}
        </svg>
        {tip && <div className="tooltip" style={{left: tip.x+14, top: tip.y-10}}>{tip.content}</div>}
      </div>
    </div>
  );
}

/* ===================== Year-end projection ===================== */
function YearEndProjection({ data, refDate, metric, label, unit = 'kWh', betterDown = false }) {
  const result = useMemo(() => {
    if (!data || !data.length) return null;
    const year = parseInt(refDate.slice(0,4));
    const refDay = refDate.slice(5);
    const ytdRows = data.filter(r => r.year === year && r.date.slice(5) <= refDay);
    if (ytdRows.length < 10) return null;
    const dayOfYear = (() => { const dt = new Date(refDate+'T00:00:00'); const start = new Date(Date.UTC(year,0,1)); return Math.floor((dt-start)/86400000)+1; })();
    const ytdTotal = ytdRows.reduce((a,r) => a + metric(r), 0);
    const dailyAvg = ytdTotal / ytdRows.length;
    const isLeap = (year%4===0 && year%100!==0) || year%400===0;
    const daysInYear = isLeap ? 366 : 365;
    const projected = dailyAvg * daysInYear;
    // Average of prior full years
    const years = [...new Set(data.map(r=>r.year))].filter(y => y !== year);
    const totals = years.map(y => {
      const rows = data.filter(r => r.year === y);
      if (rows.length < 300) return null;
      return rows.reduce((a,r)=>a+metric(r),0);
    }).filter(v => v != null);
    const avgPrior = totals.length ? totals.reduce((a,v)=>a+v,0)/totals.length : null;
    const delta = avgPrior ? (projected - avgPrior)/avgPrior : null;
    return { projected, avgPrior, delta, dayOfYear, daysInYear };
  }, [data, refDate]);

  if (!result) return null;
  const good = result.delta != null && (betterDown ? result.delta < 0 : result.delta > 0);
  return (
    <div className="insight-card">
      <div className="insight-head">
        <span className="eyebrow">projection fin d'année</span>
        {result.delta != null && (
          <span className={'wp-delta ' + (good ? 'good' : 'bad')}>
            {result.delta > 0 ? '+' : ''}{(result.delta*100).toFixed(1)}% vs moy.
          </span>
        )}
      </div>
      <div className="insight-sub">
        <strong>{label}</strong> au rythme actuel : <strong>{fmt.k(result.projected,0)} {unit}</strong>
        {result.avgPrior != null && <> (moyenne années précédentes : {fmt.k(result.avgPrior,0)} {unit})</>}
        {' '}— basé sur {result.dayOfYear}/{result.daysInYear} jours
      </div>
    </div>
  );
}

/* ===================== 7-day solar production forecast ===================== */
function SolarForecastPanel({ data }) {
  const [forecast, setForecast] = useState(null);
  const k = useMemo(() => {
    if (!data || !data.length) return 0;
    let pv = 0, cl = 0;
    for (const r of data) { pv += (r.pvAuto||0)+(r.pvSold||0); cl += clearness(r); }
    return cl > 0 ? pv / cl : 0;
  }, [data]);

  useEffect(() => {
    if (!k) return;
    (async () => {
      try {
        const cached = JSON.parse(localStorage.getItem('solar-forecast-cache') || 'null');
        if (cached && Date.now() - cached.at < 3*3600*1000) { setForecast(cached.days); return; }
      } catch {}
      try {
        const url = `https://api.open-meteo.com/v1/forecast?latitude=${LAT_I}&longitude=${LON_I}&daily=cloud_cover_mean,weather_code&timezone=Europe%2FParis&forecast_days=7`;
        const r = await fetch(url); const j = await r.json();
        const days = j.daily.time.map((d,i) => ({
          date: d,
          cloud: j.daily.cloud_cover_mean ? j.daily.cloud_cover_mean[i] : 50,
        }));
        try { localStorage.setItem('solar-forecast-cache', JSON.stringify({ at: Date.now(), days })); } catch {}
        setForecast(days);
      } catch {}
    })();
  }, [k]);

  if (!forecast || !k) return null;
  const estimates = forecast.map(d => k * Math.max(0.05, (100-(d.cloud??50))/100));
  const maxV = Math.max(...estimates, 1);
  const DAYS = ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'];
  return (
    <div className="insight-card">
      <div className="insight-head">
        <span className="eyebrow">prévision production · 7 jours</span>
        <span className="mono small dim">{fmt.k(estimates.reduce((a,v)=>a+v,0),0)} kWh estimés</span>
      </div>
      <div className="forecast-row">
        {forecast.map((d, i) => {
          const dt = new Date(d.date+'T00:00:00');
          const h = Math.max(4, (estimates[i]/maxV)*44);
          return (
            <div key={d.date} className="forecast-day">
              <div className="forecast-bar-wrap"><div className="forecast-bar" style={{height:h}} /></div>
              <div className="forecast-val mono">{estimates[i].toFixed(0)}</div>
              <div className="forecast-lbl">{DAYS[dt.getDay()]}</div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ===================== Compare 2 periods side-by-side ===================== */
function ComparePeriodsPanel({ data, currentRange }) {
  const [open, setOpen] = useState(false);
  const [rangeB, setRangeB] = useState(() => {
    const from = new Date(currentRange.from), to = new Date(currentRange.to);
    const fromB = new Date(from); fromB.setFullYear(fromB.getFullYear()-1);
    const toB = new Date(to); toB.setFullYear(toB.getFullYear()-1);
    return { from: fromB.toISOString().slice(0,10), to: toB.toISOString().slice(0,10) };
  });

  const sumA = useMemo(() => aggregate(filterRange(data, currentRange.from, currentRange.to)), [data, currentRange]);
  const sumB = useMemo(() => aggregate(filterRange(data, rangeB.from, rangeB.to)), [data, rangeB]);

  const rows = [
    { label: 'Consommation', a: sumA.conso, b: sumB.conso, unit: 'kWh', betterDown: true },
    { label: 'Production PV', a: sumA.pvTotal, b: sumB.pvTotal, unit: 'kWh', betterDown: false },
    { label: 'Autonomie', a: sumA.autoprod*100, b: sumB.autoprod*100, unit: '%', betterDown: false },
    { label: 'Coût réseau', a: sumA.costHome, b: sumB.costHome, unit: '€', betterDown: true },
    { label: 'Km électriques', a: sumA.kmTotal, b: sumB.kmTotal, unit: 'km', betterDown: false },
    { label: 'CO₂ évité', a: sumA.co2+sumA.veCo2Avoided, b: sumB.co2+sumB.veCo2Avoided, unit: 'kg', betterDown: false },
  ];

  return (
    <div className="compare-wrap">
      <button className="drill-close" onClick={() => setOpen(o=>!o)}>
        {open ? 'Fermer la comparaison ✕' : '⇄ Comparer 2 périodes'}
      </button>
      {open && (
        <div className="compare-panel">
          <div className="compare-heads">
            <div className="compare-head-a">
              <span className="eyebrow">Période A (active)</span>
              <div className="mono small">{fmt.date(currentRange.from)} → {fmt.date(currentRange.to)}</div>
            </div>
            <div className="compare-head-b">
              <span className="eyebrow">Période B</span>
              <div className="compare-dates">
                <input type="date" value={rangeB.from} onChange={e => setRangeB(r => ({...r, from: e.target.value}))} />
                <span className="dim">→</span>
                <input type="date" value={rangeB.to} onChange={e => setRangeB(r => ({...r, to: e.target.value}))} />
              </div>
            </div>
          </div>
          <div className="compare-rows">
            {rows.map((r, i) => {
              const delta = r.b !== 0 ? (r.a - r.b) / Math.abs(r.b) : null;
              const good = delta != null && (r.betterDown ? delta < 0 : delta > 0);
              return (
                <div key={i} className="compare-row">
                  <span className="compare-label">{r.label}</span>
                  <span className="compare-val">{fmt.k(r.a,1)} {r.unit}</span>
                  <span className="compare-val dim">{fmt.k(r.b,1)} {r.unit}</span>
                  {delta != null && (
                    <span className={'delta ' + (good ? 'up' : 'down')}>{delta>0?'+':''}{(delta*100).toFixed(1)}%</span>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { SoilingCheck, YearEndProjection, SolarForecastPanel, ComparePeriodsPanel });
