// ========================================================
//  Views: Översikt, Leads, Budget & Kanaler, Analys, Inställningar
// ========================================================

const R = Recharts;
const {
  LineChart, Line, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip,
  ResponsiveContainer, Legend, ReferenceLine, Cell, PieChart, Pie
} = R;

const COLOR_SE = "#1e5fa3";
const COLOR_NO = "#c83b3b";
const COLOR_ACCENT = "#2f6a5f";

// helpers ------------------------------------------------------
function getLeadsFor(market, period){
  return getLeadsInRange(market, period.fromIso, period.toIso);
}
function getBudgetFor(market, period){
  if(market === "BOTH"){
    const b = getBudgetForResolvedPeriod(market, period);
    return { SE: b.SE, NO: b.NO, combined: b.combined };
  }
  return getBudgetForResolvedPeriod(market, period);
}
function summarize(leads, budget, market){
  const total = leads.length;
  const conv = leads.filter(l => l.status === "Konverterad").length;
  const intakt = leads.reduce((a,l)=> a + (l.ordervarde||0), 0);
  let ongoingTotal = 0, setupTotal = 0, monthlyBudgetTotal = 0;
  if(budget){
    if(market === "BOTH"){
      const c = budget.combined;
      ongoingTotal = c.ongoing;
      setupTotal = c.setup;
      monthlyBudgetTotal = c.monthlyBudget;
    } else {
      ongoingTotal = budget.ongoing;
      setupTotal = budget.setup;
      monthlyBudgetTotal = budget.monthlyBudget;
    }
  }
  // tracked leads = leads with attribution confidence Hög or Medel
  const tracked = leads.filter(l => l.attribution_confidence === "Hög" || l.attribution_confidence === "Medel").length;
  return {
    total,
    conv,
    convRate: total ? (conv/total)*100 : 0,
    intakt,
    tracked,
    trackedRate: total ? (tracked/total)*100 : 0,
    budget: ongoingTotal,
    setup: setupTotal,
    monthlyBudget: monthlyBudgetTotal,
    cpl: total ? ongoingTotal/total : 0,
  };
}
function pctDelta(curr, prev){
  if(prev === null || prev === undefined || prev === 0) return null;
  const diff = ((curr - prev) / Math.abs(prev)) * 100;
  return {
    text: `${diff >= 0 ? "+" : ""}${diff.toFixed(1).replace(".",",")} %`,
    dir: diff >= 0.5 ? "up" : diff <= -0.5 ? "down" : "flat",
  };
}
// Compute a prev-period summary (using resolved.prev range)
function summarizePrev(market, period){
  const prevPeriod = {
    from: period.prev.from, to: period.prev.to,
    fromIso: period.prev.fromIso, toIso: period.prev.toIso,
    monthKeys: [],
  };
  // Re-derive monthKeys for prev range
  let cursor = startOfMonth(period.prev.from);
  while(cursor <= period.prev.to){
    prevPeriod.monthKeys.push(`${cursor.getFullYear()}-${cursor.getMonth()}`);
    cursor = new Date(cursor.getFullYear(), cursor.getMonth()+1, 1);
  }
  const leads = getLeadsInRange(market, period.prev.fromIso, period.prev.toIso);
  const budget = market === "BOTH"
    ? getBudgetForResolvedPeriod(market, prevPeriod)
    : getBudgetForResolvedPeriod(market, prevPeriod);
  return summarize(leads, budget, market);
}

// =============== ÖVERSIKT ====================================
function OversiktView({ market, period }){
  const leads = getLeadsFor(market, period);
  const budget = getBudgetFor(market, period);
  const summary = summarize(leads, budget, market);
  const prevSummary = summarizePrev(market, period);

  // build daily series across [from, to]
  const dailySeries = useMemo(() => {
    const arr = [];
    let cursor = new Date(period.from);
    while(cursor <= period.to){
      const ds = isoDate(cursor);
      if(market === "BOTH"){
        const se = LEADS_DB[`${cursor.getFullYear()}-${cursor.getMonth()}`]?.SE?.filter(l => l.datum === ds).length || 0;
        const no = LEADS_DB[`${cursor.getFullYear()}-${cursor.getMonth()}`]?.NO?.filter(l => l.datum === ds).length || 0;
        arr.push({ day: ds, label: shortLabelForTick(cursor, period.days), SE: se, NO: no });
      } else {
        const c = leads.filter(l => l.datum === ds).length;
        arr.push({ day: ds, label: shortLabelForTick(cursor, period.days), leads: c });
      }
      cursor = addDays(cursor, 1);
    }
    return arr;
  }, [market, period, leads]);

  function shortLabelForTick(d, totalDays){
    if(totalDays <= 31) return String(d.getDate());
    return `${String(d.getDate()).padStart(2,"0")}/${MONTHS_SV[d.getMonth()].slice(0,3).toLowerCase()}`;
  }

  // by channel mini
  const byChannel = useMemo(() => {
    const map = {};
    leads.forEach(l => { map[l.kanal] = (map[l.kanal]||0) + 1; });
    return Object.entries(map).map(([k,v]) => ({ kanal:k, leads:v })).sort((a,b)=>b.leads-a.leads);
  }, [leads]);

  // recent leads
  const recent = useMemo(() => {
    return [...leads].sort((a,b) => (b.datum+b.tid).localeCompare(a.datum+a.tid)).slice(0, 6);
  }, [leads]);

  // tracking quality breakdown
  const trackingStats = useMemo(() => {
    const out = { total: leads.length, Hög: 0, Medel: 0, Låg: 0, Okänd: 0 };
    leads.forEach(l => { out[l.attribution_confidence || "Okänd"] = (out[l.attribution_confidence || "Okänd"]||0) + 1; });
    out.säkerProcent = out.total ? (out.Hög / out.total) * 100 : 0;
    return out;
  }, [leads]);

  return (
    <>
      <Topbar
        title={market === "BOTH" ? "Översikt · Samlad vy" : market === "SE" ? "Översikt · EasyTull Sverige" : "Översikt · EasyToll Norge"}
        subtitle={period.isCalendarMonth
          ? "Månadens prestanda i ett ögonkast. Klicka på en kanal eller kort för djupare analys."
          : `Vald period: ${period.days} dagar. Budget och CPL är prorerade från månadskostnader.`}
        market={market}
        periodLabel={period.label}
        right={
          <div className="flex items-center gap-2">
            <Btn variant="outline" size="sm">Exportera PDF</Btn>
            <Btn variant="primary" size="sm">+ Ny lead</Btn>
          </div>
        }
      />

      {/* Partial period banner */}
      {!period.isCalendarMonth && (
        <div className="bg-[#fbf8f2] border border-[#ecdfc2] rounded-xl px-4 py-2.5 mb-5 text-[12.5px] text-[#7a5520] flex items-center gap-3">
          <span className="w-6 h-6 rounded-full bg-[#e89548]/15 text-[#9b5a16] flex items-center justify-center text-[12px] font-medium shrink-0">i</span>
          <span>
            Budget och CPL är beräknade på vald period ({period.days} dagar) — fasta retainers prorerade. Hel månadsbudget är <strong className="num">{fmtNum(summary.monthlyBudget)} kr</strong>.
          </span>
        </div>
      )}

      {/* KPI strip */}
      <div className="grid grid-cols-6 gap-3 mb-6">
        <KpiCard
          label="Annonsbudget"
          value={fmtNum(summary.budget)}
          suffix={market === "BOTH" ? "kr" : (market==="NO"?"NOK":"SEK")}
          sub={period.isCalendarMonth ? "Löpande spend" : `Prorerad · ${period.days} dgr`}
          delta={prevSummary ? pctDelta(summary.budget, prevSummary.budget)?.text : null}
          deltaDirection={prevSummary ? pctDelta(summary.budget, prevSummary.budget)?.dir : null}
          accent="bg-accent"
        />
        <KpiCard
          label="Leads"
          value={fmtNum(summary.total)}
          sub={`vs ${period.prev.label}`}
          delta={prevSummary ? pctDelta(summary.total, prevSummary.total)?.text : null}
          deltaDirection={prevSummary ? pctDelta(summary.total, prevSummary.total)?.dir : null}
          accent="bg-sky-500"
        />
        <KpiCard
          label="Kostnad per lead"
          value={fmtNum(summary.cpl)}
          suffix={market === "BOTH" ? "kr" : (market==="NO"?"NOK":"SEK")}
          sub="CPL · ex. setup"
          delta={prevSummary && prevSummary.cpl ? pctDelta(summary.cpl, prevSummary.cpl)?.text : null}
          deltaDirection={prevSummary && prevSummary.cpl
            ? (pctDelta(summary.cpl, prevSummary.cpl)?.dir === "up" ? "down" : pctDelta(summary.cpl, prevSummary.cpl)?.dir === "down" ? "up" : "flat") // inverse: lower CPL = good
            : null}
          accent="bg-amber-500"
        />
        <KpiCard
          label="Konvertering"
          value={summary.convRate.toFixed(1).replace(".",",")}
          suffix="%"
          sub={`${summary.conv} av ${summary.total} leads`}
          delta={prevSummary ? pctDelta(summary.convRate, prevSummary.convRate)?.text : null}
          deltaDirection={prevSummary ? pctDelta(summary.convRate, prevSummary.convRate)?.dir : null}
          accent="bg-violet-500"
        />
        <KpiCard
          label="Est. intäkt"
          value={fmtNum(summary.intakt)}
          suffix={market === "BOTH" ? "kr" : (market==="NO"?"NOK":"SEK")}
          sub="från konverterade"
          delta={prevSummary ? pctDelta(summary.intakt, prevSummary.intakt)?.text : null}
          deltaDirection={prevSummary ? pctDelta(summary.intakt, prevSummary.intakt)?.dir : null}
          accent="bg-emerald-500"
        />
        <KpiCard
          label="Spårade leads"
          value={fmtNum(summary.tracked)}
          sub={`${fmtPct(summary.trackedRate, 0)} av total`}
          delta={prevSummary ? pctDelta(summary.tracked, prevSummary.tracked)?.text : null}
          deltaDirection={prevSummary ? pctDelta(summary.tracked, prevSummary.tracked)?.dir : null}
          accent="bg-teal-500"
        />
      </div>

      {/* Chart + side */}
      <div className="grid grid-cols-3 gap-5 mb-6">
        <Card title="Leads per dag" subtitle={market==="BOTH" ? "EasyTull SE vs EasyToll NO" : `Dagliga leads under ${period.label}`} className="col-span-2">
          <div className="h-[280px] -ml-2">
            <ResponsiveContainer>
              {market === "BOTH" ? (
                <LineChart data={dailySeries} margin={{ top: 10, right: 14, left: 0, bottom: 0 }}>
                  <CartesianGrid stroke="#ecebe4" strokeDasharray="3 3" vertical={false}/>
                  <XAxis dataKey="label" axisLine={false} tickLine={false}/>
                  <YAxis axisLine={false} tickLine={false} width={28}/>
                  <Tooltip content={<ChartTooltip/>}/>
                  <Legend iconType="circle" iconSize={8} verticalAlign="top" align="right" height={28}/>
                  <Line type="monotone" dataKey="SE" name="EasyTull SE" stroke={COLOR_SE} strokeWidth={2} dot={{ r:2.5 }} activeDot={{ r: 4 }}/>
                  <Line type="monotone" dataKey="NO" name="EasyToll NO" stroke={COLOR_NO} strokeWidth={2} dot={{ r:2.5 }} activeDot={{ r: 4 }}/>
                </LineChart>
              ) : (
                <LineChart data={dailySeries} margin={{ top: 10, right: 14, left: 0, bottom: 0 }}>
                  <defs>
                    <linearGradient id="ll" x1="0" y1="0" x2="0" y2="1">
                      <stop offset="0%" stopColor={COLOR_ACCENT} stopOpacity={0.25}/>
                      <stop offset="100%" stopColor={COLOR_ACCENT} stopOpacity={0}/>
                    </linearGradient>
                  </defs>
                  <CartesianGrid stroke="#ecebe4" strokeDasharray="3 3" vertical={false}/>
                  <XAxis dataKey="label" axisLine={false} tickLine={false}/>
                  <YAxis axisLine={false} tickLine={false} width={28}/>
                  <Tooltip content={<ChartTooltip/>}/>
                  <Line type="monotone" dataKey="leads" name="Leads" stroke={COLOR_ACCENT} strokeWidth={2.2} dot={{ r:2.5 }} activeDot={{ r: 4 }} fill="url(#ll)"/>
                </LineChart>
              )}
            </ResponsiveContainer>
          </div>
        </Card>

        <Card title={market==="BOTH" ? "SE vs NO" : "Toppkanaler"} subtitle={market==="BOTH" ? "Snabb jämförelse" : "Leads-fördelning"}>
          {market === "BOTH" ? <CompareSEvsNO period={period}/> : <ChannelMix data={byChannel}/>}
        </Card>
      </div>

      {/* Trackingstatus + GA4 note */}
      <div className="grid grid-cols-3 gap-5 mb-6">
        <Card title="Trackingstatus" subtitle="Hur säker är attribution på vald period?" className="col-span-2">
          <div className="grid grid-cols-5 gap-3 mt-1">
            <TrackStatCell label="Totalt" value={trackingStats.total} tone="ink"/>
            <TrackStatCell label="Hög" value={trackingStats["Hög"]} sub={trackingStats.total ? `${((trackingStats["Hög"]/trackingStats.total)*100).toFixed(0)} %` : "0 %"} tone="good"/>
            <TrackStatCell label="Medel" value={trackingStats["Medel"]} sub={trackingStats.total ? `${((trackingStats["Medel"]/trackingStats.total)*100).toFixed(0)} %` : "0 %"} tone="warn"/>
            <TrackStatCell label="Låg" value={trackingStats["Låg"]} sub={trackingStats.total ? `${((trackingStats["Låg"]/trackingStats.total)*100).toFixed(0)} %` : "0 %"} tone="bad"/>
            <TrackStatCell label="Okänd" value={trackingStats["Okänd"]} sub={trackingStats.total ? `${((trackingStats["Okänd"]/trackingStats.total)*100).toFixed(0)} %` : "0 %"} tone="mute"/>
          </div>
          <div className="mt-5 pt-4 border-t border-paper-200 flex items-center gap-4">
            <div className="display num text-[28px] text-ink-900 leading-none">{trackingStats["Hög"]}</div>
            <div className="text-[13px] text-ink-700 leading-snug flex-1">
              av {trackingStats.total} leads har <strong>säker attribution</strong> i vald period
              <span className="text-ink-500"> · {fmtPct(trackingStats.säkerProcent, 0)}</span>
            </div>
            {/* progress bar */}
            <div className="w-[180px]">
              <div className="h-2 bg-paper-100 rounded-full overflow-hidden flex">
                {["Hög","Medel","Låg","Okänd"].map(k => {
                  const w = trackingStats.total ? (trackingStats[k]/trackingStats.total)*100 : 0;
                  const color = k==="Hög"?"#3a8a5a":k==="Medel"?"#d6a44e":k==="Låg"?"#c25a5f":"#c4cad3";
                  return <div key={k} style={{ width:`${w}%`, background: color }}/>;
                })}
              </div>
              <div className="flex justify-between text-[10px] text-ink-500 mt-1.5">
                <span>Hög</span><span>Medel</span><span>Låg</span><span>Okänd</span>
              </div>
            </div>
          </div>
        </Card>

        <div className="bg-[#fbf8f2] border border-[#ecdfc2] rounded-xl p-5 flex flex-col gap-3">
          <div className="flex items-center gap-2">
            <span className="w-7 h-7 rounded-full bg-[#e89548]/15 text-[#9b5a16] flex items-center justify-center text-sm font-medium">i</span>
            <span className="eyebrow text-[#9b5a16]">GA4 vs Fluent Forms</span>
          </div>
          <p className="text-[13px] text-ink-800 leading-snug">
            GA4 visar kanalstatistik, men varje enskilt lead behöver egen spårningsdata från Fluent Forms för säker attribution.
          </p>
          <ul className="text-[12px] text-ink-600 space-y-1.5 mt-1">
            <li className="flex gap-2"><span className="text-[#9b5a16]">·</span>Lägg till hidden fields i Fluent Forms för <code className="font-mono text-[11px] bg-white/60 px-1 rounded">first_landing_page</code></li>
            <li className="flex gap-2"><span className="text-[#9b5a16]">·</span>Skicka med <code className="font-mono text-[11px] bg-white/60 px-1 rounded">utm_*</code>, <code className="font-mono text-[11px] bg-white/60 px-1 rounded">gclid</code>, <code className="font-mono text-[11px] bg-white/60 px-1 rounded">gbraid</code>, <code className="font-mono text-[11px] bg-white/60 px-1 rounded">wbraid</code></li>
            <li className="flex gap-2"><span className="text-[#9b5a16]">·</span>Behåll original <code className="font-mono text-[11px] bg-white/60 px-1 rounded">document.referrer</code> som hidden field</li>
          </ul>
        </div>
      </div>

      {/* Recent leads */}
      <Card title="Senaste leads" subtitle="De 6 mest nyligen registrerade" right={<a className="text-xs text-accent-ink underline-offset-2 hover:underline cursor-pointer">Visa alla →</a>}>
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="text-left text-ink-500 text-[11px] tracking-wider uppercase border-b border-paper-200">
                <th className="py-2 font-medium">Datum</th>
                <th className="py-2 font-medium">Källa</th>
                <th className="py-2 font-medium">Säkerhet</th>
                <th className="py-2 font-medium">Tjänst</th>
                <th className="py-2 font-medium">Kontakt</th>
                {market==="BOTH" && <th className="py-2 font-medium">Marknad</th>}
                <th className="py-2 font-medium">Status</th>
                <th className="py-2 font-medium text-right">Värde</th>
              </tr>
            </thead>
            <tbody>
              {recent.map(l => (
                <tr key={l.id} className="border-b border-paper-100 last:border-0 hover:bg-paper-50">
                  <td className="py-2.5 num text-ink-700">{l.datum} <span className="text-ink-400">·</span> {l.tid}</td>
                  <td className="py-2.5"><SourceBadge source={l.kalla_kategori || "Okänd"} size="sm"/></td>
                  <td className="py-2.5"><ConfidenceBadge level={l.attribution_confidence || "Okänd"} size="sm"/></td>
                  <td className="py-2.5 text-ink-700">{l.tjanst}</td>
                  <td className="py-2.5 text-ink-700">{l.kontakt}</td>
                  {market==="BOTH" && <td className="py-2.5"><MarketTag market={l.land}/></td>}
                  <td className="py-2.5"><StatusPill status={l.status} onChange={()=>{}}/></td>
                  <td className="py-2.5 text-right num text-ink-700">{l.ordervarde ? fmtNum(l.ordervarde) : <span className="text-ink-400">—</span>}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>
    </>
  );
}

function ChannelMix({ data }){
  const max = Math.max(...data.map(d => d.leads), 1);
  return (
    <div className="space-y-3 mt-1">
      {data.map(d => (
        <div key={d.kanal}>
          <div className="flex justify-between text-[12.5px] mb-1">
            <span className="text-ink-700">{d.kanal}</span>
            <span className="num text-ink-500">{d.leads}</span>
          </div>
          <div className="h-2 bg-paper-100 rounded-full overflow-hidden">
            <div className="h-full rounded-full" style={{ width: `${(d.leads/max)*100}%`, background: d.kanal.startsWith("Organisk") ? COLOR_ACCENT : d.kanal==="Direkt" ? "#8a93a5" : "#3a4150" }}></div>
          </div>
        </div>
      ))}
    </div>
  );
}

function TrackStatCell({ label, value, sub, tone }){
  const tones = {
    ink:  "bg-paper-50 border-paper-200 text-ink-900",
    good: "bg-accent-soft/60 border-accent/15 text-accent-ink",
    warn: "bg-amber-50 border-amber-200 text-amber-900",
    bad:  "bg-rose-50 border-rose-200 text-rose-900",
    mute: "bg-paper-100 border-paper-200 text-ink-600",
  };
  return (
    <div className={`rounded-lg border px-3 py-3 ${tones[tone]}`}>
      <div className="eyebrow opacity-70">{label}</div>
      <div className="display num text-[24px] leading-none mt-1.5">{value}</div>
      {sub && <div className="text-[11px] opacity-70 num mt-1">{sub}</div>}
    </div>
  );
}

function CompareSEvsNO({ period }){
  const seL = getLeadsInRange("SE", period.fromIso, period.toIso);
  const noL = getLeadsInRange("NO", period.fromIso, period.toIso);
  const seB = getBudgetForResolvedPeriod("SE", period);
  const noB = getBudgetForResolvedPeriod("NO", period);
  const seBT = seB.ongoing;
  const noBT = noB.ongoing;
  const rows = [
    { label: "Leads",      se: seL.length, no: noL.length, fmt: v=>fmtNum(v) },
    { label: "Konvertering", se: seL.length ? (seL.filter(l=>l.status==="Konverterad").length/seL.length)*100 : 0, no: noL.length ? (noL.filter(l=>l.status==="Konverterad").length/noL.length)*100 : 0, fmt: v=>fmtPct(v) },
    { label: "CPL",        se: seL.length ? seBT/seL.length : 0, no: noL.length ? noBT/noL.length : 0, fmt: (v,m)=>fmtMoney(v, m) },
    { label: "Intäkt",     se: seL.reduce((a,l)=>a+(l.ordervarde||0),0), no: noL.reduce((a,l)=>a+(l.ordervarde||0),0), fmt:(v,m)=>fmtMoney(v,m) },
  ];
  return (
    <div className="mt-1 space-y-3">
      {rows.map(r => {
        const winner = r.label === "CPL" ? (r.se < r.no ? "SE" : "NO") : (r.se > r.no ? "SE" : "NO");
        return (
          <div key={r.label} className="border-b border-paper-100 pb-3 last:border-0 last:pb-0">
            <div className="eyebrow text-ink-500 mb-1.5">{r.label}</div>
            <div className="grid grid-cols-2 gap-3">
              <div className={`flex items-baseline gap-2 ${winner==="SE" ? "" : "opacity-60"}`}>
                <FlagSE size={11}/>
                <span className="display num text-[18px] text-ink-900">{r.fmt(r.se, "SE")}</span>
                {winner==="SE" && <span className="text-[10px] text-accent-ink ml-auto px-1.5 py-0.5 bg-accent-soft rounded-full">Bäst</span>}
              </div>
              <div className={`flex items-baseline gap-2 ${winner==="NO" ? "" : "opacity-60"}`}>
                <FlagNO size={11}/>
                <span className="display num text-[18px] text-ink-900">{r.fmt(r.no, "NO")}</span>
                {winner==="NO" && <span className="text-[10px] text-accent-ink ml-auto px-1.5 py-0.5 bg-accent-soft rounded-full">Bäst</span>}
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

// =============== LEADS ===========================================
const EMPTY_FILTER = { kanal:"alla", tjanst:"alla", status:"alla", kalla:"alla", confidence:"alla", landning:"alla", form:"alla", sok:"" };

function filterIsEmpty(f){
  return Object.keys(EMPTY_FILTER).every(k => f[k] === EMPTY_FILTER[k]);
}
function describeFilter(f){
  const bits = [];
  if(f.kanal && f.kanal !== "alla") bits.push(f.kanal);
  if(f.tjanst && f.tjanst !== "alla") bits.push(f.tjanst);
  if(f.status && f.status !== "alla") bits.push(f.status);
  if(f.kalla && f.kalla !== "alla") bits.push(f.kalla);
  if(f.confidence && f.confidence !== "alla") bits.push("Säkerhet: "+f.confidence);
  if(f.landning && f.landning !== "alla") bits.push(f.landning);
  if(f.form && f.form !== "alla") bits.push("Formulär: "+f.form);
  if(f.sok) bits.push(`"${f.sok}"`);
  return bits.join(" · ") || "Inga aktiva filter";
}
function loadPresets(userEmail){
  try {
    const raw = localStorage.getItem(`easytull:filters:${userEmail}`);
    return raw ? JSON.parse(raw) : [];
  } catch(_) { return []; }
}
function savePresets(userEmail, presets){
  try { localStorage.setItem(`easytull:filters:${userEmail}`, JSON.stringify(presets)); } catch(_) {}
}

function LeadsView({ market, period, setLeadsState, leadsState, currentUser, isAdmin }){
  // we keep edits to leads in leadsState (overrides on top of LEADS_DB)
  const baseLeads = useMemo(() => {
    const arr = getLeadsFor(market, period).map(l => ({ ...l }));
    // apply overrides
    return arr
      .map(l => leadsState[l.id] ? { ...l, ...leadsState[l.id] } : l)
      .filter(l => !l.deleted_at);
  }, [market, period, leadsState]);

  const [filter, setFilter] = useState(EMPTY_FILTER);
  const [openEdit, setOpenEdit] = useState(null);
  const [openAdd, setOpenAdd] = useState(false);

  // ===== Per-user saved presets =====
  const [presets, setPresets] = useState(() => loadPresets(currentUser));
  const [activePresetId, setActivePresetId] = useState(null);
  const [openSave, setOpenSave] = useState(false);
  const [presetName, setPresetName] = useState("");
  useEffect(() => { setPresets(loadPresets(currentUser)); setActivePresetId(null); }, [currentUser]);
  useEffect(() => { savePresets(currentUser, presets); }, [currentUser, presets]);

  function applyPreset(p){
    setFilter(p.filter);
    setActivePresetId(p.id);
  }
  function clearFilter(){
    setFilter(EMPTY_FILTER);
    setActivePresetId(null);
  }
  function saveCurrentAsPreset(){
    if(!presetName.trim()) return;
    const id = `p-${Date.now()}-${Math.floor(Math.random()*999)}`;
    const p = { id, name: presetName.trim(), favorit: false, filter: {...filter} };
    setPresets(arr => [...arr, p]);
    setActivePresetId(id);
    setPresetName("");
    setOpenSave(false);
  }
  function toggleFavorit(id){
    setPresets(arr => arr.map(p => p.id === id ? { ...p, favorit: !p.favorit } : p));
  }
  function deletePreset(id){
    setPresets(arr => arr.filter(p => p.id !== id));
    if(activePresetId === id) setActivePresetId(null);
  }
  function renamePreset(id, name){
    setPresets(arr => arr.map(p => p.id === id ? { ...p, name } : p));
  }
  const sortedPresets = useMemo(() => [...presets].sort((a,b) => (b.favorit?1:0) - (a.favorit?1:0)), [presets]);
  const filterChanged = !filterIsEmpty(filter);

  // If user edits filter manually, drop active preset
  function updateFilter(patch){
    setFilter(f => ({ ...f, ...patch }));
    setActivePresetId(null);
  }

  const filtered = baseLeads.filter(l => {
    if(filter.kanal !== "alla" && l.kanal !== filter.kanal) return false;
    if(filter.tjanst !== "alla" && l.tjanst !== filter.tjanst) return false;
    if(filter.status !== "alla" && l.status !== filter.status) return false;
    if(filter.kalla !== "alla" && l.kalla_kategori !== filter.kalla) return false;
    if(filter.confidence !== "alla" && l.attribution_confidence !== filter.confidence) return false;
    if(filter.landning !== "alla" && (l.first_landing_page || l.landning) !== filter.landning) return false;
    if(filter.form !== "alla" && l.form_page !== filter.form) return false;
    if(filter.sok && !(l.anteckning||"").toLowerCase().includes(filter.sok.toLowerCase()) && !l.tjanst.toLowerCase().includes(filter.sok.toLowerCase()) && !l.kanal.toLowerCase().includes(filter.sok.toLowerCase()) && !(l.kampanj||"").toLowerCase().includes(filter.sok.toLowerCase()) && !(l.sokord||"").toLowerCase().includes(filter.sok.toLowerCase())) return false;
    return true;
  }).sort((a,b) => (b.datum+b.tid).localeCompare(a.datum+a.tid));

  const allKanaler = market === "BOTH"
    ? [...new Set([...KANALER_SE, ...KANALER_NO])]
    : (market === "SE" ? KANALER_SE : KANALER_NO);

  const uniqueKallor    = useMemo(()=> [...new Set(baseLeads.map(l => l.kalla_kategori).filter(Boolean))], [baseLeads]);
  const uniqueLandningar= useMemo(()=> [...new Set(baseLeads.map(l => l.first_landing_page || l.landning).filter(Boolean))].slice(0,30), [baseLeads]);
  const uniqueForms     = useMemo(()=> [...new Set(baseLeads.map(l => l.form_page).filter(Boolean))].slice(0,30), [baseLeads]);

  // KPI summary for filtered set
  const kpis = useMemo(() => {
    const total = filtered.length;
    const konv = filtered.filter(l => l.status === "Konverterad").length;
    const pag  = filtered.filter(l => l.status === "Pågående").length;
    // Order values are mixed currencies in BOTH mode; sum and label accordingly.
    const ordSE = filtered.filter(l => l.land === "SE").reduce((a,l)=>a+(l.ordervarde||0),0);
    const ordNO = filtered.filter(l => l.land === "NO").reduce((a,l)=>a+(l.ordervarde||0),0);
    return { total, konv, pag, ordSE, ordNO };
  }, [filtered]);

  function updateLead(id, patch){
    const base = baseLeads.find(l => l.id === id) || {};
    const saved = { ...base, ...patch, id };
    upsertLeadIntoDb(saved);
    setLeadsState(s => ({ ...s, [id]: { ...(s[id]||{}), ...patch } }));
    window.EASYTULL_BACKEND?.persistLead(saved)
      .catch(err => console.warn("Lead kunde inte sparas i Supabase.", err));
  }
  function addLead(newLead){
    upsertLeadIntoDb(newLead);
    setLeadsState(s => ({ ...s, [newLead.id]: newLead }));
    window.EASYTULL_BACKEND?.persistLead(newLead)
      .catch(err => console.warn("Lead kunde inte sparas i Supabase.", err));
  }
  function deleteLead(lead){
    if(!isAdmin || !lead) return;
    const ok = window.confirm("Radera leaden från dashboarden?");
    if(!ok) return;
    const deleted = { ...lead, deleted_at: new Date().toISOString() };
    setLeadsState(s => ({ ...s, [lead.id]: { ...(s[lead.id]||{}), deleted_at: deleted.deleted_at } }));
    window.EASYTULL_BACKEND?.persistLead(deleted)
      .catch(err => console.warn("Lead kunde inte raderas i Supabase.", err));
  }

  return (
    <>
      <Topbar
        title="Leads"
        subtitle="Alla leads från annonser, SEO, direktkontakt och formulär. Klicka på en rad för att redigera."
        market={market}
        periodLabel={period.label}
        right={
          <div className="flex items-center gap-2">
            <Btn variant="outline" size="sm">Exportera CSV</Btn>
            <Btn variant="primary" size="sm" onClick={()=>setOpenAdd(true)}>+ Ny lead</Btn>
          </div>
        }
      />

      {/* Small KPI strip */}
      <div className="grid grid-cols-4 gap-3 mb-4">
        <MiniKpi label="Totalt leads"      value={fmtNum(kpis.total)} dot="bg-ink-700"/>
        <MiniKpi label="Konverterade"      value={fmtNum(kpis.konv)}   sub={kpis.total ? `${((kpis.konv/kpis.total)*100).toFixed(0).replace(".",",")} %` : "0 %"} dot="bg-accent" tint="accent"/>
        <MiniKpi label="Pågående"          value={fmtNum(kpis.pag)}    sub={kpis.total ? `${((kpis.pag/kpis.total)*100).toFixed(0).replace(".",",")} %` : "0 %"} dot="bg-sky-500"/>
        <MiniKpi
          label="Est. ordervärde"
          value={
            market === "BOTH"
              ? <span className="flex items-baseline gap-2"><span className="num">{fmtNum(kpis.ordSE)}</span><span className="text-[11px] text-ink-500">SEK</span><span className="num text-ink-700">/ {fmtNum(kpis.ordNO)}</span><span className="text-[11px] text-ink-500">NOK</span></span>
              : <span className="flex items-baseline gap-1.5"><span className="num">{fmtNum(market === "SE" ? kpis.ordSE : kpis.ordNO)}</span><span className="text-[11px] text-ink-500">{market === "NO" ? "NOK" : "SEK"}</span></span>
          }
          dot="bg-emerald-500"
          tint="accent"
          big
        />
      </div>

      {/* Saved filter presets (per-user) */}
      <Card className="mb-3">
        <div className="flex flex-wrap items-center gap-2 py-2.5">
          <span className="eyebrow text-ink-500 mr-1">Sparade filter</span>
          {sortedPresets.length === 0 && (
            <span className="text-[12px] text-ink-400 italic">Inga sparade filter än — spara nuvarande för att börja.</span>
          )}
          {sortedPresets.map(p => (
            <PresetChip
              key={p.id}
              preset={p}
              active={p.id === activePresetId}
              onApply={()=>applyPreset(p)}
              onToggleFavorit={()=>toggleFavorit(p.id)}
              onDelete={()=>deletePreset(p.id)}
              onRename={(name)=>renamePreset(p.id, name)}
            />
          ))}
          <div className="ml-auto flex items-center gap-2">
            {filterChanged && (
              <button
                onClick={clearFilter}
                className="text-[12px] text-ink-600 hover:text-ink-900 inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-md hover:bg-paper-100"
              >
                <svg width="11" height="11" viewBox="0 0 12 12"><path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>
                Rensa filter
              </button>
            )}
            <button
              onClick={()=>{ setOpenSave(true); setPresetName(""); }}
              disabled={!filterChanged}
              className={`text-[12px] inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md border transition
                ${filterChanged ? "border-paper-300 text-ink-800 hover:bg-paper-100 hover:border-ink-600" : "border-paper-200 text-ink-400 cursor-not-allowed"}`}
            >
              <svg width="11" height="11" viewBox="0 0 12 12"><path d="M3 2h5l2 2v6H3z M4 2v3h4V2 M5 8h2" stroke="currentColor" strokeWidth="1.2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
              Spara filter
            </button>
          </div>
        </div>
        {activePresetId && (
          <div className="mt-2 text-[11px] text-ink-500 truncate">
            Aktivt filter: <span className="text-ink-800">{(presets.find(p=>p.id===activePresetId)||{}).name}</span> <span className="text-ink-400">·</span> {describeFilter(filter)}
          </div>
        )}
      </Card>

      {/* Filter bar */}
      <Card className="mb-5">
        <div className="flex flex-wrap items-center gap-x-4 gap-y-3 py-2.5">
          <div className="flex-1 min-w-[220px] relative">
            <svg width="14" height="14" viewBox="0 0 16 16" className="absolute left-3 top-1/2 -translate-y-1/2 text-ink-400"><circle cx="7" cy="7" r="5" stroke="currentColor" fill="none" strokeWidth="1.5"/><path d="M11 11l3 3" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>
            <input
              placeholder="Sök i tjänst, kanal, kampanj, sökord eller anteckning…"
              value={filter.sok}
              onChange={e=>updateFilter({sok:e.target.value})}
              className="w-full bg-paper-50 border border-paper-200 rounded-lg pl-9 pr-3 py-2 text-sm focus:outline-none focus:border-ink-600"
            />
          </div>
          <FilterSelect label="Kanal" value={filter.kanal} onChange={v=>updateFilter({kanal:v})} options={["alla", ...allKanaler]}/>
          <FilterSelect label="Tjänst" value={filter.tjanst} onChange={v=>updateFilter({tjanst:v})} options={["alla", ...TJANSTER]}/>
          <FilterSelect label="Status" value={filter.status} onChange={v=>updateFilter({status:v})} options={["alla", ...STATUSAR]}/>
          <FilterSelect label="Källa" value={filter.kalla} onChange={v=>updateFilter({kalla:v})} options={["alla", ...uniqueKallor]}/>
          <FilterSelect label="Säkerhet" value={filter.confidence} onChange={v=>updateFilter({confidence:v})} options={["alla", ...CONFIDENCE_NIVAER]}/>
          <FilterSelect label="Landningssida" value={filter.landning} onChange={v=>updateFilter({landning:v})} options={["alla", ...uniqueLandningar]}/>
          <FilterSelect label="Formulärsida" value={filter.form} onChange={v=>updateFilter({form:v})} options={["alla", ...uniqueForms]}/>
          <div className="text-[12px] text-ink-500 ml-auto num">{filtered.length} av {baseLeads.length} leads</div>
        </div>
      </Card>

      {/* Save preset modal */}
      {openSave && (
        <div className="fixed inset-0 z-30 bg-ink-900/50 flex items-center justify-center p-6" onClick={()=>setOpenSave(false)}>
          <div className="bg-white w-[460px] max-w-full rounded-xl border border-paper-200 shadow-2xl" onClick={e=>e.stopPropagation()}>
            <div className="px-6 pt-6 pb-3 border-b border-paper-200">
              <div className="eyebrow text-ink-500">Spara filter</div>
              <h3 className="display text-[22px] text-ink-900 mt-0.5">Namnge ditt filter</h3>
              <p className="text-[12px] text-ink-500 mt-1.5">Sparas bara för dig ({(ANVANDARE.find(u=>u.email===currentUser)||{}).namn}).</p>
            </div>
            <div className="p-6 space-y-3">
              <input
                autoFocus
                value={presetName}
                onChange={e=>setPresetName(e.target.value)}
                onKeyDown={e=>{ if(e.key==="Enter") saveCurrentAsPreset(); }}
                placeholder="T.ex. Mina konverterade Google Ads-leads"
                className="w-full bg-paper-50 border border-paper-200 rounded-lg px-3 py-2.5 text-sm focus:outline-none focus:border-ink-600"
              />
              <div className="bg-paper-50 border border-paper-200 rounded-lg px-3 py-2.5">
                <div className="eyebrow text-ink-500 mb-1.5">Filter som sparas</div>
                <div className="text-[12px] text-ink-700 leading-snug">{describeFilter(filter)}</div>
              </div>
            </div>
            <div className="flex items-center justify-end gap-2 px-6 pb-6 border-t border-paper-200 pt-3">
              <Btn variant="ghost" onClick={()=>setOpenSave(false)}>Avbryt</Btn>
              <Btn variant="primary" onClick={saveCurrentAsPreset}>Spara</Btn>
            </div>
          </div>
        </div>
      )}

      {/* Table */}
      <Card>
        <div className="overflow-x-auto scroll-thin-light">
          <table className="w-full text-sm" style={{ minWidth: market==="BOTH" ? "1500px" : "1420px" }}>
            <thead>
              <tr className="text-left text-ink-500 text-[11px] tracking-wider uppercase border-b border-paper-200">
                <th className="py-2.5 font-medium pr-3">När</th>
                <th className="py-2.5 font-medium pr-3">Källa</th>
                <th className="py-2.5 font-medium pr-3">Säkerhet</th>
                <th className="py-2.5 font-medium pr-3">Kanal</th>
                <th className="py-2.5 font-medium pr-3">Kampanj / Sökord</th>
                <th className="py-2.5 font-medium pr-3">Landningssida</th>
                <th className="py-2.5 font-medium pr-3">Formulärsida</th>
                <th className="py-2.5 font-medium pr-3">Tjänst</th>
                {market==="BOTH" && <th className="py-2.5 font-medium pr-3">Marknad</th>}
                <th className="py-2.5 font-medium pr-3">Status</th>
                <th className="py-2.5 font-medium pr-6 text-right">Ordervärde</th>
                <th className="py-2.5 font-medium pl-2">Anteckning</th>
                {isAdmin && <th className="py-2.5 font-medium pl-3 text-right">Admin</th>}
              </tr>
            </thead>
            <tbody>
              {filtered.map(l => {
                const converted = l.status === "Konverterad";
                const landingShown = l.first_landing_page || l.landning;
                return (
                  <tr
                    key={l.id}
                    onClick={()=>setOpenEdit(l)}
                    className="border-b border-paper-100 last:border-0 hover:bg-paper-50 cursor-pointer align-top"
                  >
                    <td className="py-3 pr-3 whitespace-nowrap">
                      <div className="num text-ink-800 leading-tight">{l.datum}</div>
                      <div className="text-[11.5px] text-ink-500 num">{l.tid} <span className="text-ink-400">·</span> {l.veckodag.slice(0,3)}</div>
                    </td>
                    <td className="py-3 pr-3"><SourceBadge source={l.kalla_kategori || "Okänd"} size="sm"/></td>
                    <td className="py-3 pr-3"><ConfidenceBadge level={l.attribution_confidence || "Okänd"} size="sm"/></td>
                    <td className="py-3 pr-3 text-ink-700 whitespace-nowrap">{l.kanal}</td>
                    <td className="py-3 pr-3 max-w-[220px]">
                      {l.kampanj ? <div className="text-ink-800 leading-tight truncate" title={l.kampanj}>{l.kampanj}</div> : null}
                      {l.sokord ? <div className="text-[12px] text-ink-500 font-mono leading-tight truncate" title={l.sokord}>{l.sokord}</div> : (!l.kampanj && <span className="text-ink-400">—</span>)}
                    </td>
                    <td className="py-3 pr-3 max-w-[200px]">
                      {landingShown
                        ? <code className="text-[12px] text-ink-600 bg-paper-100 px-1.5 py-0.5 rounded truncate inline-block max-w-full" title={landingShown}>{landingShown}</code>
                        : <span className="text-ink-400 text-[11px] italic">Ej spårad</span>}
                    </td>
                    <td className="py-3 pr-3 max-w-[180px]">
                      {l.form_page
                        ? <code className="text-[12px] text-ink-600 bg-paper-100 px-1.5 py-0.5 rounded truncate inline-block max-w-full" title={l.form_page}>{l.form_page}</code>
                        : <span className="text-ink-400 text-[11px] italic">Saknas</span>}
                    </td>
                    <td className="py-3 pr-3 text-ink-700 whitespace-nowrap">{l.tjanst}</td>
                    {market==="BOTH" && <td className="py-3 pr-3"><MarketTag market={l.land}/></td>}
                    <td className="py-3 pr-3"><StatusPill status={l.status} onChange={s=>updateLead(l.id,{status:s})}/></td>
                    <td className="py-3 pr-6 text-right whitespace-nowrap">
                      {l.ordervarde ? (
                        <span className={`num inline-flex items-baseline gap-1 ${converted ? "display text-[16px] text-accent-ink font-medium" : "text-ink-700"}`}>
                          {converted && <span className="text-[10px] text-accent-ink/70 mr-0.5">▲</span>}
                          {fmtNum(l.ordervarde)}
                          <span className={`text-[10.5px] ${converted ? "text-accent-ink/60" : "text-ink-400"}`}>{l.land === "NO" ? "NOK" : "SEK"}</span>
                        </span>
                      ) : <span className="text-ink-400">—</span>}
                    </td>
                    <td className="py-3 pl-2 text-ink-500 w-[200px] max-w-[200px]">
                      {l.anteckning
                        ? <span className="block truncate" title={l.anteckning}>{l.anteckning}</span>
                        : <span className="text-ink-400">—</span>}
                    </td>
                    {isAdmin && (
                      <td className="py-3 pl-3 text-right">
                        <button
                          onClick={(e)=>{ e.stopPropagation(); deleteLead(l); }}
                          className="inline-flex items-center justify-center gap-1.5 rounded-lg border border-rose-100 bg-rose-50 px-2.5 py-1.5 text-[12px] text-rose-700 transition hover:bg-rose-100 hover:border-rose-200"
                          title="Radera lead"
                        >
                          <svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
                            <path d="M2.5 4h11"/>
                            <path d="M6.5 2.5h3l.8 1.5"/>
                            <path d="M5 6v6M8 6v6M11 6v6"/>
                            <path d="M4 4l.6 9.5h6.8L12 4"/>
                          </svg>
                          Radera
                        </button>
                      </td>
                    )}
                  </tr>
                );
              })}
              {filtered.length === 0 && (
                <tr><td colSpan={(market==="BOTH"?12:11) + (isAdmin ? 1 : 0)}><Empty>Inga leads matchar filtret.</Empty></td></tr>
              )}
            </tbody>
          </table>
        </div>
      </Card>

      {openEdit && (
        <LeadModal
          lead={openEdit}
          onClose={()=>setOpenEdit(null)}
          onSave={(patch)=>{ updateLead(openEdit.id, patch); setOpenEdit(null); }}
        />
      )}
      {openAdd && (
        <LeadModal
          isNew
          period={period}
          defaultMarket={market === "BOTH" ? "SE" : market}
          onClose={()=>setOpenAdd(false)}
          onSave={(newLead)=>{ addLead(newLead); setOpenAdd(false); }}
        />
      )}
    </>
  );
}

function FilterSelect({ label, value, onChange, options }){
  return (
    <label className="flex items-center gap-2 text-[12px] text-ink-500">
      {label}:
      <select
        value={value}
        onChange={e=>onChange(e.target.value)}
        className="bare bg-paper-50 border border-paper-200 rounded-lg px-2.5 py-1.5 text-[13px] text-ink-700 focus:outline-none focus:border-ink-600"
      >
        {options.map(o => <option key={o} value={o}>{o === "alla" ? "Alla" : o}</option>)}
      </select>
    </label>
  );
}

function PresetChip({ preset, active, onApply, onToggleFavorit, onDelete, onRename }){
  const [menuOpen, setMenuOpen] = useState(false);
  const [editing, setEditing] = useState(false);
  const [name, setName] = useState(preset.name);
  const ref = useRef(null);
  useEffect(() => { setName(preset.name); }, [preset.name]);
  useEffect(()=>{
    function close(e){ if(ref.current && !ref.current.contains(e.target)) { setMenuOpen(false); } }
    document.addEventListener("mousedown", close);
    return ()=>document.removeEventListener("mousedown", close);
  },[]);

  function commitRename(){
    if(name.trim() && name.trim() !== preset.name) onRename(name.trim());
    else setName(preset.name);
    setEditing(false);
  }

  return (
    <div className="relative inline-flex" ref={ref}>
      <button
        onClick={(e)=>{
          if(editing) return;
          onApply();
        }}
        className={`inline-flex items-center gap-1.5 text-[12.5px] pl-2 pr-1 py-1 rounded-full border transition
          ${active
            ? "bg-ink-900 text-paper-50 border-ink-900"
            : "bg-white text-ink-800 border-paper-300 hover:border-ink-600 hover:bg-paper-50"}`}
      >
        <button
          onClick={(e)=>{ e.stopPropagation(); onToggleFavorit(); }}
          className="inline-flex items-center"
          title={preset.favorit ? "Ta bort från favoriter" : "Markera som favorit"}
        >
          {preset.favorit
            ? <svg width="12" height="12" viewBox="0 0 12 12" className={active ? "text-amber-300" : "text-amber-500"}><path d="M6 1l1.6 3.3 3.4.5-2.5 2.5.6 3.5L6 9l-3.1 1.8.6-3.5L1 4.8l3.4-.5z" fill="currentColor"/></svg>
            : <svg width="12" height="12" viewBox="0 0 12 12" className={active ? "text-paper-300" : "text-ink-400"}><path d="M6 1l1.6 3.3 3.4.5-2.5 2.5.6 3.5L6 9l-3.1 1.8.6-3.5L1 4.8l3.4-.5z" stroke="currentColor" strokeWidth="1" fill="none" strokeLinejoin="round"/></svg>
          }
        </button>
        {editing ? (
          <input
            autoFocus
            value={name}
            onChange={e=>setName(e.target.value)}
            onBlur={commitRename}
            onKeyDown={e=>{ if(e.key==="Enter") commitRename(); if(e.key==="Escape"){ setName(preset.name); setEditing(false);} }}
            className="bg-transparent text-[12.5px] focus:outline-none w-[120px]"
            onClick={e=>e.stopPropagation()}
          />
        ) : (
          <span className="px-0.5">{preset.name}</span>
        )}
        <span
          role="button"
          onClick={(e)=>{ e.stopPropagation(); setMenuOpen(o=>!o); }}
          className={`inline-flex items-center justify-center w-5 h-5 rounded-full ${active ? "hover:bg-white/15" : "hover:bg-paper-200"}`}
          title="Mer"
        >
          <svg width="11" height="11" viewBox="0 0 12 12" className="opacity-70">
            <circle cx="2.5" cy="6" r="1" fill="currentColor"/><circle cx="6" cy="6" r="1" fill="currentColor"/><circle cx="9.5" cy="6" r="1" fill="currentColor"/>
          </svg>
        </span>
      </button>
      {menuOpen && (
        <div className="absolute z-20 left-0 top-full mt-1 bg-white border border-paper-200 rounded-lg shadow-lg overflow-hidden min-w-[180px]">
          <button onClick={(e)=>{ e.stopPropagation(); setMenuOpen(false); setEditing(true); }} className="w-full text-left px-3 py-2 text-[13px] text-ink-700 hover:bg-paper-100">Byt namn</button>
          <button onClick={(e)=>{ e.stopPropagation(); onToggleFavorit(); setMenuOpen(false); }} className="w-full text-left px-3 py-2 text-[13px] text-ink-700 hover:bg-paper-100">
            {preset.favorit ? "Ta bort från favoriter" : "Markera som favorit"}
          </button>
          <button onClick={(e)=>{ e.stopPropagation(); onDelete(); setMenuOpen(false); }} className="w-full text-left px-3 py-2 text-[13px] text-rose-700 hover:bg-rose-50 border-t border-paper-200">Radera</button>
        </div>
      )}
    </div>
  );
}

function MiniKpi({ label, value, sub, dot, tint, big }){
  return (
    <div className={`rounded-xl border px-4 py-3 flex items-center gap-3 ${tint==="accent" ? "bg-accent-soft/40 border-accent/15" : "bg-white border-paper-200"}`}>
      <span className={`w-1.5 h-1.5 rounded-full ${dot}`}></span>
      <div className="flex-1 min-w-0">
        <div className="eyebrow text-ink-500">{label}</div>
        <div className={`display num leading-none mt-1 text-ink-900 ${big ? "text-[22px]" : "text-[24px]"}`}>{value}</div>
      </div>
      {sub && <div className="text-[11px] text-ink-500 num shrink-0">{sub}</div>}
    </div>
  );
}

function LeadModal({ lead, isNew, period, defaultMarket, onClose, onSave }){
  const [form, setForm] = useState(() => {
    if(isNew){
      const now = new Date();
      const land = defaultMarket || "SE";
      // Pick a date inside the resolved period — clamp today into [from, to]
      const clamped = now < period.from ? period.from : now > period.to ? period.to : now;
      const y = clamped.getFullYear();
      const m = clamped.getMonth();
      const dd = clamped.getDate();
      return {
        id: `${land}-${y}-${m+1}-new-${Date.now()}`,
        datum: `${y}-${String(m+1).padStart(2,"0")}-${String(dd).padStart(2,"0")}`,
        tid: `${String(now.getHours()).padStart(2,"0")}:${String(now.getMinutes()).padStart(2,"0")}`,
        veckodag: VECKODAGAR_FULL[(clamped.getDay()+6)%7],
        kanal: land === "SE" ? "Google Ads SE" : "Google Ads NO",
        kalla: "Google",
        kampanj: "",
        sokord: "",
        landning: "",
        kontakt: "E-post",
        tjanst: "Import",
        land,
        status: "Pågående",
        ordervarde: 0,
        anteckning: "",
      };
    }
    return { ...lead };
  });
  function set(k,v){ setForm(f => ({ ...f, [k]: v })); }
  const allKanaler = form.land === "SE" ? KANALER_SE : KANALER_NO;

  return (
    <div className="fixed inset-0 z-30 bg-ink-900/50 flex items-center justify-center p-6" onClick={onClose}>
      <div className="bg-white w-[720px] max-w-full max-h-[90vh] overflow-y-auto rounded-xl border border-paper-200 shadow-2xl" onClick={e=>e.stopPropagation()}>
        <div className="flex items-center justify-between px-6 pt-6 pb-4 border-b border-paper-200 sticky top-0 bg-white">
          <div>
            <div className="eyebrow text-ink-500">{isNew ? "Ny lead" : "Redigera lead"}</div>
            <h3 className="display text-[22px] text-ink-900 mt-0.5">{isNew ? "Registrera ny lead" : `Lead · ${form.datum} ${form.tid}`}</h3>
          </div>
          <button onClick={onClose} className="text-ink-500 hover:text-ink-900 text-xl leading-none">×</button>
        </div>
        <div className="p-6 space-y-5">
          <div>
            <div className="eyebrow text-ink-500 mb-3">Grundinformation</div>
            <div className="grid grid-cols-2 gap-4">
              <Field label="Datum"><input type="date" value={form.datum} onChange={e=>set("datum",e.target.value)} className="modalInput"/></Field>
              <Field label="Tid"><input type="time" value={form.tid} onChange={e=>set("tid",e.target.value)} className="modalInput"/></Field>
              <Field label="Marknad">
                <select value={form.land} onChange={e=>{ const v = e.target.value; set("land", v); set("kanal", v==="SE"?"Google Ads SE":"Google Ads NO"); }} className="modalInput bare">
                  <option value="SE">🇸🇪 Sverige</option>
                  <option value="NO">🇳🇴 Norge</option>
                </select>
              </Field>
              <Field label="Kanal">
                <select value={form.kanal} onChange={e=>set("kanal",e.target.value)} className="modalInput bare">
                  {allKanaler.map(k => <option key={k} value={k}>{k}</option>)}
                </select>
              </Field>
              <Field label="Kontaktsätt">
                <select value={form.kontakt} onChange={e=>set("kontakt",e.target.value)} className="modalInput bare">
                  {KONTAKTSATT.map(k => <option key={k} value={k}>{k}</option>)}
                </select>
              </Field>
              <Field label="Tjänst">
                <select value={form.tjanst} onChange={e=>set("tjanst",e.target.value)} className="modalInput bare">
                  {TJANSTER.map(k => <option key={k} value={k}>{k}</option>)}
                </select>
              </Field>
            </div>
          </div>

          <div>
            <div className="eyebrow text-ink-500 mb-3 flex items-center gap-2">
              Pineberry-spårning
              <span className="text-[10px] font-normal normal-case tracking-normal text-ink-400">· UTM &amp; kampanjdata</span>
            </div>
            <div className="grid grid-cols-2 gap-4">
              <Field label="Källa">
                <input list="kalla-list" value={form.kalla || ""} onChange={e=>set("kalla",e.target.value)} className="modalInput" placeholder="Google · Bing · Direkt · LinkedIn"/>
                <datalist id="kalla-list"><option value="Google"/><option value="Bing"/><option value="Direkt"/><option value="LinkedIn"/><option value="Facebook"/></datalist>
              </Field>
              <Field label="Kampanj">
                <input value={form.kampanj || ""} onChange={e=>set("kampanj",e.target.value)} className="modalInput" placeholder="T.ex. 'Tullombud Import · SE'"/>
              </Field>
              <Field label="Sökord">
                <input value={form.sokord || ""} onChange={e=>set("sokord",e.target.value)} className="modalInput font-mono" placeholder="t.ex. tullombud import"/>
              </Field>
              <Field label="Landningssida">
                <input value={form.landning || ""} onChange={e=>set("landning",e.target.value)} className="modalInput font-mono" placeholder="/tjanster/import"/>
              </Field>
            </div>
          </div>

          <div>
            <div className="eyebrow text-ink-500 mb-3">Utfall</div>
            <div className="grid grid-cols-2 gap-4">
              <Field label="Status">
                <select value={form.status} onChange={e=>set("status",e.target.value)} className="modalInput bare">
                  {STATUSAR.map(k => <option key={k} value={k}>{k}</option>)}
                </select>
              </Field>
              <Field label={`Ordervärde (${form.land === "NO" ? "NOK" : "SEK"})`}>
                <input type="number" value={form.ordervarde} onChange={e=>set("ordervarde", Number(e.target.value))} className="modalInput num"/>
              </Field>
              <div className="col-span-2">
                <Field label="Anteckning">
                  <textarea value={form.anteckning} onChange={e=>set("anteckning",e.target.value)} rows={4} className="modalInput" placeholder="T.ex. 'Brådskande sändning från Hamburg, behöver offert imorgon.'"/>
                </Field>
              </div>
            </div>
          </div>

          {/* ============ Spårningsdata (read-only — kommer från Fluent Forms + GTM) ============ */}
          {!isNew && (
            <div>
              <div className="eyebrow text-ink-500 mb-3 flex items-center gap-2">
                Spårningsdata
                <span className="text-[10px] font-normal normal-case tracking-normal text-ink-400">· Från Fluent Forms / GTM</span>
                <span className="ml-auto inline-flex items-center gap-2">
                  <SourceBadge source={form.kalla_kategori || "Okänd"} size="sm"/>
                  <ConfidenceBadge level={form.attribution_confidence || "Okänd"} size="sm"/>
                </span>
              </div>
              <div className="bg-paper-50 border border-paper-200 rounded-lg overflow-hidden">
                <TrackField label="Source URL" value={form.source_url} mono/>
                <TrackField label="First landing page" value={form.first_landing_page} mono/>
                <TrackField label="Form page" value={form.form_page} mono/>
                <TrackField label="Original referrer" value={form.original_referrer} mono/>
                <TrackField label="utm_source" value={form.utm_source} mono/>
                <TrackField label="utm_medium" value={form.utm_medium} mono/>
                <TrackField label="utm_campaign" value={form.utm_campaign} mono/>
                <TrackField label="utm_term" value={form.utm_term} mono/>
                <TrackField label="utm_content" value={form.utm_content} mono/>
                <TrackField label="gclid" value={form.gclid} mono truncate/>
                <TrackField label="gbraid" value={form.gbraid} mono truncate/>
                <TrackField label="wbraid" value={form.wbraid} mono truncate/>
                <TrackField label="gad_source" value={form.gad_source} mono/>
                <TrackField label="gad_campaignid" value={form.gad_campaignid} mono/>
                <TrackField label="Traffic source" value={form.traffic_source} mono/>
                <TrackField label="Traffic medium" value={form.traffic_medium} mono/>
                <TrackField label="Attribution confidence" value={form.attribution_confidence}/>
              </div>
              {form.scenario && (
                <div className="mt-2 text-[11px] text-ink-500 italic">Scenario: {form.scenario}</div>
              )}
            </div>
          )}
        </div>
        <div className="flex items-center justify-end gap-2 px-6 pb-6 pt-2 border-t border-paper-200 sticky bottom-0 bg-white">
          <Btn variant="ghost" onClick={onClose}>Avbryt</Btn>
          <Btn variant="primary" onClick={()=>onSave(form)}>{isNew ? "Skapa lead" : "Spara ändringar"}</Btn>
        </div>
        <style>{`.modalInput{ width:100%; background:#fbfaf7; border:1px solid #ecebe4; border-radius:8px; padding:8px 12px; font-size:14px; color:#13161b; outline:none; }
        .modalInput:focus{ border-color:#13161b; }`}</style>
      </div>
    </div>
  );
}

function Field({ label, children }){
  return (
    <label className="flex flex-col gap-1.5">
      <span className="eyebrow text-ink-500">{label}</span>
      {children}
    </label>
  );
}

function TrackField({ label, value, mono, truncate }){
  const empty = value === null || value === undefined || value === "";
  return (
    <div className="grid grid-cols-[180px_1fr] gap-3 px-3.5 py-2 border-b border-paper-200 last:border-0 items-baseline">
      <span className="text-[11.5px] text-ink-500">{label}</span>
      {empty ? (
        <span className="text-[11.5px] italic text-ink-400">Ej spårad</span>
      ) : (
        <span className={`text-[12.5px] text-ink-800 ${mono ? "font-mono" : ""} ${truncate ? "truncate" : "break-all"}`} title={String(value)}>
          {String(value)}
        </span>
      )}
    </div>
  );
}

// =============== BUDGET ==========================================
function BudgetView({ market, period, budgetState, setBudgetState }){
  const editable = period.isCalendarMonth && period.monthKey;
  const editKey = editable ? period.monthKey : null;
  const baseBudget = editKey ? BUDGET_DB[editKey] : null;

  // Merged budget for the editable month (only relevant in editable mode)
  const merged = editable ? {
    SE: { ...baseBudget.SE, ...(budgetState[`${editKey}-SE`]||{}) },
    NO: { ...baseBudget.NO, ...(budgetState[`${editKey}-NO`]||{}) },
  } : null;

  function updateBudget(mkt, patch){
    if(!editKey) return;
    // Persist into BUDGET_DB AND budgetState so getBudgetForResolvedPeriod sees changes
    const key = `${editKey}-${mkt}`;
    setBudgetState(s => ({ ...s, [key]: { ...(s[key]||{}), ...patch } }));
    Object.assign(BUDGET_DB[editKey][mkt], patch);
    window.EASYTULL_BACKEND?.persistBudget({ id: `${editKey}:${mkt}`, ...BUDGET_DB[editKey][mkt] })
      .catch(err => console.warn("Budget kunde inte sparas i Supabase.", err));
  }

  // Resolved period budget (always available — pro-rated for partial)
  const resolved = useMemo(() => getBudgetForResolvedPeriod(market, period), [market, period, budgetState]);
  const summary = market === "BOTH" ? resolved.combined : resolved;

  return (
    <>
      <Topbar
        title="Budget & kanaler"
        subtitle={editable
          ? "Logga månadens marknadsföringskostnader per kanal och marknad. Anteckningar hjälper er fånga vad som testades."
          : "Vald period är inte en hel kalendermånad — budgeten visas prorerad. Välj en specifik månad för att redigera."}
        market={market}
        periodLabel={period.label}
      />

      {/* Resolved period overview */}
      <PeriodBudgetOverview period={period} summary={summary} market={market}/>

      {!editable && (
        <div className="bg-[#fbf8f2] border border-[#ecdfc2] rounded-xl px-4 py-2.5 mb-5 text-[12.5px] text-[#7a5520] flex items-center gap-3">
          <span className="w-6 h-6 rounded-full bg-[#e89548]/15 text-[#9b5a16] flex items-center justify-center text-[12px] font-medium shrink-0">i</span>
          <span>
            Du visar en sammanfattning för <strong>{period.label}</strong>. Redigering av budget sker per kalendermånad — välj t.ex. <strong>{monthLabel(period.from)}</strong> i periodväljaren.
          </span>
        </div>
      )}

      {/* Budget forms — only when editing a calendar month */}
      {editable && (
        <div className={`grid gap-5 mb-6 ${market === "BOTH" ? "grid-cols-2" : "grid-cols-1"}`}>
          {(market === "SE" || market === "BOTH") && (
            <BudgetFormCard market="SE" budget={merged.SE} onChange={p=>updateBudget("SE", p)}/>
          )}
          {(market === "NO" || market === "BOTH") && (
            <BudgetFormCard market="NO" budget={merged.NO} onChange={p=>updateBudget("NO", p)}/>
          )}
        </div>
      )}

      {/* Engångskostnader (setup) */}
      <SetupCard period={period} market={market} summary={summary} editable={editable}/>

      {/* Chart */}
      <Card title="Fördelning per kanal" subtitle={market === "BOTH" ? "Grupperade staplar — SE vs NO" : `Kostnadsfördelning ${period.label}`} className="mb-5">
        <BudgetChart market={market} period={period} resolved={resolved}/>
      </Card>

      {/* Notes (only in editable month mode) */}
      {editable && (
        <div className={`grid gap-5 ${market === "BOTH" ? "grid-cols-2" : "grid-cols-1"}`}>
          {(market === "SE" || market === "BOTH") && (
            <NotesCard market="SE" value={merged.SE.anteckning} onChange={v=>updateBudget("SE",{anteckning:v})}/>
          )}
          {(market === "NO" || market === "BOTH") && (
            <NotesCard market="NO" value={merged.NO.anteckning} onChange={v=>updateBudget("NO",{anteckning:v})}/>
          )}
        </div>
      )}
    </>
  );
}

function PeriodBudgetOverview({ period, summary, market }){
  const cur = market === "BOTH" ? "kr" : (market === "NO" ? "NOK" : "SEK");
  return (
    <div className="grid grid-cols-4 gap-3 mb-5">
      <BudgetCell label="Löpande för perioden" value={fmtNum(summary.ongoing)} cur={cur} tone="ink" sub={period.isCalendarMonth ? "Hel månad" : `Prorerad · ${period.days} dgr`}/>
      <BudgetCell label="Variabel (Ads + övrigt)" value={fmtNum(summary.variable)} cur={cur} tone="mute" sub="Google Ads · Övrigt"/>
      <BudgetCell label="Fasta retainers" value={fmtNum(summary.fixed)} cur={cur} tone="mute" sub="SEO · Ads management"/>
      <BudgetCell label="Månadsbudget (full)" value={fmtNum(summary.monthlyBudget)} cur={cur} tone="accent" sub="Hela månaden / månaderna"/>
    </div>
  );
}
function BudgetCell({ label, value, cur, sub, tone }){
  const tones = {
    ink: "bg-white border-paper-200 text-ink-900",
    mute: "bg-paper-50 border-paper-200 text-ink-800",
    accent: "bg-accent-soft/40 border-accent/15 text-accent-ink",
  };
  return (
    <div className={`rounded-xl border px-4 py-3 ${tones[tone]}`}>
      <div className="eyebrow opacity-70">{label}</div>
      <div className="display num text-[24px] leading-none mt-1.5">{value} <span className="text-[11px] opacity-60">{cur}</span></div>
      {sub && <div className="text-[11px] opacity-70 mt-1.5">{sub}</div>}
    </div>
  );
}

function BudgetChart({ market, period, resolved }){
  if(market === "BOTH"){
    const data = [
      { kanal: "Google Ads",    SE: resolved.SE.googleAds,     NO: resolved.NO.googleAds },
      { kanal: "SEO (retainer)",SE: resolved.SE.seo,           NO: resolved.NO.seo },
      { kanal: "Ads mgmt",      SE: resolved.SE.adsManagement, NO: resolved.NO.adsManagement },
      { kanal: "Övrigt",        SE: resolved.SE.ovrigt,        NO: resolved.NO.ovrigt },
    ];
    return (
      <div className="h-[280px] -ml-2">
        <ResponsiveContainer>
          <BarChart data={data} margin={{ top: 14, right: 14, left: 0, bottom: 0 }}>
            <CartesianGrid stroke="#ecebe4" strokeDasharray="3 3" vertical={false}/>
            <XAxis dataKey="kanal" axisLine={false} tickLine={false}/>
            <YAxis axisLine={false} tickLine={false} width={48} tickFormatter={v=>v>=1000?`${Math.round(v/1000)}k`:v}/>
            <Tooltip content={<ChartTooltip valueFormatter={v=>fmtNum(v)+" kr"}/>}/>
            <Legend iconType="circle" iconSize={8} verticalAlign="top" align="right" height={28}/>
            <Bar dataKey="SE" name="EasyTull SE" fill={COLOR_SE} radius={[4,4,0,0]} maxBarSize={42}/>
            <Bar dataKey="NO" name="EasyToll NO" fill={COLOR_NO} radius={[4,4,0,0]} maxBarSize={42}/>
          </BarChart>
        </ResponsiveContainer>
      </div>
    );
  }
  const data = [
    { kanal: "Google Ads",    value: resolved.googleAds },
    { kanal: "SEO (retainer)",value: resolved.seo },
    { kanal: "Ads mgmt",      value: resolved.adsManagement },
    { kanal: "Övrigt",        value: resolved.ovrigt },
  ];
  return (
    <div className="h-[280px] -ml-2">
      <ResponsiveContainer>
        <BarChart data={data} margin={{ top: 14, right: 14, left: 0, bottom: 0 }}>
          <CartesianGrid stroke="#ecebe4" strokeDasharray="3 3" vertical={false}/>
          <XAxis dataKey="kanal" axisLine={false} tickLine={false}/>
          <YAxis axisLine={false} tickLine={false} width={48} tickFormatter={v=>v>=1000?`${Math.round(v/1000)}k`:v}/>
          <Tooltip content={<ChartTooltip valueFormatter={v=>fmtNum(v)+" kr"}/>}/>
          <Bar dataKey="value" name="Kostnad" fill={market === "SE" ? COLOR_SE : COLOR_NO} radius={[4,4,0,0]} maxBarSize={60}/>
        </BarChart>
      </ResponsiveContainer>
    </div>
  );
}

function SetupCard({ period, market, summary, editable }){
  const items = summary.setupItems || [];
  return (
    <Card
      title="Engångskostnader"
      subtitle="Setup, omkonfigurering, kampanjer — räknas inte in i löpande CPL/ROI"
      right={<span className="text-[12px] text-ink-500 num">Totalt {fmtNum(summary.setup)} kr i perioden</span>}
      className="mb-5"
    >
      {items.length === 0 ? (
        <div className="text-[12.5px] text-ink-500 italic py-2">Inga engångskostnader registrerade i vald period.</div>
      ) : (
        <table className="w-full text-sm">
          <thead>
            <tr className="text-left text-ink-500 text-[11px] tracking-wider uppercase border-b border-paper-200">
              <th className="py-2 font-medium">Datum</th>
              <th className="py-2 font-medium">Beskrivning</th>
              {market === "BOTH" && <th className="py-2 font-medium">Marknad</th>}
              <th className="py-2 font-medium text-right">Kostnad</th>
            </tr>
          </thead>
          <tbody>
            {items.map((s, i) => (
              <tr key={i} className="border-b border-paper-100 last:border-0">
                <td className="py-2.5 num text-ink-700">{s.datum}</td>
                <td className="py-2.5 text-ink-800">{s.namn}</td>
                {market === "BOTH" && <td className="py-2.5"><MarketTag market={s.market}/></td>}
                <td className="py-2.5 text-right num text-ink-800">{fmtNum(s.kostnad)} <span className="text-[10.5px] text-ink-400">{s.market === "NO" ? "NOK" : "SEK"}</span></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </Card>
  );
}

function BudgetFormCard({ market, budget, onChange }){
  const cur = market === "NO" ? "NOK" : "SEK";
  const ongoing = budget.googleAds + budget.seo + (budget.adsManagement||0) + budget.ovrigt;
  return (
    <Card
      title={market === "SE" ? "EasyTull · Sverige" : "EasyToll · Norge"}
      subtitle="Månadens kostnader per kanal"
      right={<span className="inline-flex items-center gap-1.5 text-xs text-ink-500">{market==="SE"?<FlagSE/>:<FlagNO/>} {cur}</span>}
    >
      <div className="space-y-3 mt-1">
        <BudgetInput label="Google Ads"      value={budget.googleAds}     cur={cur} onChange={v=>onChange({googleAds:v})} tag="Variabel"/>
        <BudgetInput label="SEO (retainer)"  value={budget.seo}           cur={cur} onChange={v=>onChange({seo:v})} tag="Fast"/>
        <BudgetInput label="Ads management"  value={budget.adsManagement||0} cur={cur} onChange={v=>onChange({adsManagement:v})} tag="Fast"/>
        <BudgetInput label="Övriga kostnader" value={budget.ovrigt}       cur={cur} onChange={v=>onChange({ovrigt:v})} tag="Variabel"/>
        <div className="flex items-baseline justify-between pt-3 mt-2 border-t border-paper-200">
          <span className="eyebrow text-ink-500">Löpande total</span>
          <span className="display num text-[26px] text-ink-900">{fmtMoney(ongoing, market)}</span>
        </div>
      </div>
    </Card>
  );
}
function BudgetInput({ label, value, cur, onChange, tag }){
  return (
    <label className="flex items-center justify-between gap-3 py-2 border-b border-paper-100 last:border-0">
      <span className="flex flex-col leading-tight">
        <span className="text-[13px] text-ink-700">{label}</span>
        {tag && <span className="text-[10px] text-ink-400 mt-0.5">{tag} · per månad</span>}
      </span>
      <div className="flex items-center gap-1.5">
        <input
          type="number"
          value={value}
          onChange={e=>onChange(Number(e.target.value))}
          className="w-32 bg-paper-50 border border-paper-200 rounded-md px-2.5 py-1.5 text-sm text-right num focus:outline-none focus:border-ink-600"
        />
        <span className="text-[12px] text-ink-500">{cur}</span>
      </div>
    </label>
  );
}

function NotesCard({ market, value, onChange }){
  return (
    <Card
      title={`Anteckningar · ${market === "SE" ? "Sverige" : "Norge"}`}
      subtitle="Vad testades den här månaden?"
      right={market==="SE" ? <FlagSE/> : <FlagNO/>}
    >
      <textarea
        value={value}
        onChange={e=>onChange(e.target.value)}
        rows={5}
        className="w-full bg-paper-50 border border-paper-200 rounded-lg px-3 py-2.5 text-[13.5px] text-ink-800 focus:outline-none focus:border-ink-600 leading-relaxed"
        placeholder="T.ex. annonstexter, sökord, landningssidor, kampanjer…"
      />
    </Card>
  );
}

// =============== ANALYS ==========================================
function AnalysView({ market, period }){
  const leads = getLeadsFor(market, period);
  const budget = getBudgetFor(market, period);

  // Per-channel stats with CPL + conversion + ROI
  const channelStats = useMemo(() => {
    const map = {};
    leads.forEach(l => {
      const k = l.kanal;
      if(!map[k]) map[k] = { kanal:k, leads:0, konv:0, intakt:0, land:l.land };
      map[k].leads++;
      if(l.status === "Konverterad") map[k].konv++;
      map[k].intakt += (l.ordervarde||0);
    });
    // assign budget to channels (ongoing only)
    function budgetForChannel(kanal, land){
      const b = market === "BOTH" ? budget[land] : budget;
      if(!b) return 0;
      if(kanal.startsWith("Google Ads")) return b.googleAds;
      if(kanal.startsWith("Organisk"))   return b.seo;
      return 0;
    }
    return Object.values(map).map(c => {
      const sp = budgetForChannel(c.kanal, c.land);
      return {
        ...c,
        cpl: c.leads ? sp/c.leads : 0,
        convRate: c.leads ? (c.konv/c.leads)*100 : 0,
        spend: sp,
        roi: sp ? ((c.intakt - sp)/sp)*100 : 0,
      };
    }).sort((a,b)=>b.leads - a.leads);
  }, [leads, budget, market]);

  // Attribution stats (per Källa kategori) + confidence breakdown + top pages
  const attribution = useMemo(() => {
    const bySource = {};
    leads.forEach(l => {
      const k = l.kalla_kategori || "Okänd";
      if(!bySource[k]) bySource[k] = { kalla:k, leads:0, konv:0, intakt:0 };
      bySource[k].leads++;
      if(l.status === "Konverterad") bySource[k].konv++;
      bySource[k].intakt += (l.ordervarde||0);
    });
    const sources = Object.values(bySource).map(s => ({
      ...s,
      convRate: s.leads ? (s.konv/s.leads)*100 : 0,
    })).sort((a,b)=>b.leads - a.leads);

    const confidence = { Hög:0, Medel:0, Låg:0, Okänd:0 };
    leads.forEach(l => { confidence[l.attribution_confidence || "Okänd"]++; });

    const byLanding = {};
    leads.forEach(l => {
      const p = l.first_landing_page || l.landning;
      if(!p) return;
      byLanding[p] = (byLanding[p]||0) + 1;
    });
    const topLanding = Object.entries(byLanding).map(([p,n])=>({ page:p, leads:n })).sort((a,b)=>b.leads-a.leads).slice(0,6);

    const byForm = {};
    leads.forEach(l => {
      const p = l.form_page;
      if(!p) return;
      byForm[p] = (byForm[p]||0) + 1;
    });
    const topForm = Object.entries(byForm).map(([p,n])=>({ page:p, leads:n })).sort((a,b)=>b.leads-a.leads).slice(0,6);

    // contact-page leads that lack first_landing_page = lost attribution signal
    const kontaktUtanLanding = leads.filter(l => /kontakt/i.test(l.form_page||"") && !l.first_landing_page).length;

    return { sources, confidence, topLanding, topForm, kontaktUtanLanding };
  }, [leads]);

  // tjänst frequency
  const tjanstStats = useMemo(() => {
    const map = {};
    TJANSTER.forEach(t => map[t] = 0);
    leads.forEach(l => map[l.tjanst]++);
    return Object.entries(map).map(([t,v]) => ({ tjanst:t, leads:v })).sort((a,b)=>b.leads - a.leads);
  }, [leads]);

  // weekday heat
  const weekdayStats = useMemo(() => {
    const map = {};
    VECKODAGAR_FULL.forEach(d => map[d] = 0);
    leads.forEach(l => map[l.veckodag]++);
    return VECKODAGAR_FULL.map(d => ({ dag:d.slice(0,3), full:d, leads: map[d] }));
  }, [leads]);

  // hour heat
  const hourStats = useMemo(() => {
    const buckets = { "06–09": 0, "09–12": 0, "12–15": 0, "15–18": 0, "18–21": 0 };
    leads.forEach(l => {
      const h = parseInt(l.tid.split(":")[0],10);
      if(h<9) buckets["06–09"]++;
      else if(h<12) buckets["09–12"]++;
      else if(h<15) buckets["12–15"]++;
      else if(h<18) buckets["15–18"]++;
      else buckets["18–21"]++;
    });
    return Object.entries(buckets).map(([k,v]) => ({ tid:k, leads:v }));
  }, [leads]);

  // SE vs NO compare for BOTH
  const seNoCompare = useMemo(() => {
    if(market !== "BOTH") return null;
    const seL = getLeadsInRange("SE", period.fromIso, period.toIso);
    const noL = getLeadsInRange("NO", period.fromIso, period.toIso);
    const seB = getBudgetForResolvedPeriod("SE", period);
    const noB = getBudgetForResolvedPeriod("NO", period);
    const seBT = seB.ongoing;
    const noBT = noB.ongoing;
    return {
      SE: {
        leads: seL.length,
        conv: seL.length ? (seL.filter(l=>l.status==="Konverterad").length/seL.length)*100 : 0,
        cpl: seL.length ? seBT/seL.length : 0,
        roi: seBT ? ((seL.reduce((a,l)=>a+(l.ordervarde||0),0) - seBT)/seBT)*100 : 0,
      },
      NO: {
        leads: noL.length,
        conv: noL.length ? (noL.filter(l=>l.status==="Konverterad").length/noL.length)*100 : 0,
        cpl: noL.length ? noBT/noL.length : 0,
        roi: noBT ? ((noL.reduce((a,l)=>a+(l.ordervarde||0),0) - noBT)/noBT)*100 : 0,
      }
    };
  }, [market, period]);

  // Automatic insights
  const insights = useMemo(() => {
    const out = [];
    if(channelStats.length){
      // lowest CPL channel (only paid channels with spend)
      const paid = channelStats.filter(c => c.spend > 0 && c.leads > 0);
      if(paid.length){
        const cheapest = paid.slice().sort((a,b)=>a.cpl-b.cpl)[0];
        const dearest  = paid.slice().sort((a,b)=>b.cpl-a.cpl)[0];
        out.push({
          tone: "good",
          title: "Lägst CPL",
          body: <><strong>{cheapest.kanal}</strong> ger lägst kostnad per lead: <span className="num">{fmtMoney(cheapest.cpl, cheapest.land)}</span> · {cheapest.leads} leads.</>
        });
        if(cheapest.kanal !== dearest.kanal){
          out.push({
            tone: "warn",
            title: "Dyrast lead",
            body: <><strong>{dearest.kanal}</strong> har den högsta CPL:n: <span className="num">{fmtMoney(dearest.cpl, dearest.land)}</span>. Värt att granska annonstext eller sökord.</>
          });
        }
      }
      // best conversion rate
      const bestConv = channelStats.slice().sort((a,b)=>b.convRate-a.convRate)[0];
      if(bestConv) out.push({
        tone: "good",
        title: "Bäst konvertering",
        body: <><strong>{bestConv.kanal}</strong> konverterar {fmtPct(bestConv.convRate)} av sina leads.</>
      });
    }
    if(tjanstStats.length){
      const top = tjanstStats[0];
      out.push({
        tone: "info",
        title: "Mest efterfrågad tjänst",
        body: <><strong>{top.tjanst}</strong> står för {top.leads} av månadens {leads.length} leads ({fmtPct((top.leads/leads.length)*100, 0)}).</>
      });
    }
    if(weekdayStats.length){
      const top = [...weekdayStats].sort((a,b)=>b.leads-a.leads)[0];
      out.push({
        tone: "info",
        title: "Starkaste veckodagen",
        body: <><strong>{top.full}</strong> ger flest leads ({top.leads} st).</>
      });
    }
    if(hourStats.length){
      const top = [...hourStats].sort((a,b)=>b.leads-a.leads)[0];
      out.push({
        tone: "info",
        title: "Bästa tid på dagen",
        body: <>Mellan <strong>{top.tid}</strong> kommer flest leads in ({top.leads} st).</>
      });
    }
    if(seNoCompare){
      const winnerLeads = seNoCompare.SE.leads >= seNoCompare.NO.leads ? "SE" : "NO";
      const winnerROI = seNoCompare.SE.roi >= seNoCompare.NO.roi ? "SE" : "NO";
      out.push({
        tone: "info",
        title: "Marknadsjämförelse",
        body: <>
          <strong>{winnerLeads === "SE" ? "EasyTull SE" : "EasyToll NO"}</strong> levererade flest leads ({seNoCompare[winnerLeads].leads} st).
          {" "}<strong>{winnerROI === "SE" ? "EasyTull SE" : "EasyToll NO"}</strong> har den bättre ROI:n ({fmtPct(seNoCompare[winnerROI].roi, 0)}).
        </>
      });
    }

    // ============= Attribution insights =============
    if(attribution.sources.length){
      const topSrc = attribution.sources[0];
      out.push({
        tone: "info",
        title: "Mest spårade källan",
        body: <><strong>{topSrc.kalla}</strong> står för flest spårade leads denna månad ({topSrc.leads} st).</>
      });
    }
    const osakra = (attribution.confidence["Låg"]||0) + (attribution.confidence["Okänd"]||0);
    if(osakra > 0){
      out.push({
        tone: "warn",
        title: "Osäker attribution",
        body: <><strong className="num">{osakra}</strong> leads saknar säker attribution denna månad.</>
      });
    }
    if(attribution.kontaktUtanLanding >= 2){
      out.push({
        tone: "warn",
        title: "Spårning tappas vid formulär",
        body: <>{attribution.kontaktUtanLanding} leads skickades från <code className="font-mono text-[11px]">/kontakt/</code> men saknar first landing page — vi vet inte varifrån de kom.</>
      });
    }
    out.push({
      tone: "good",
      title: "Förbättra spårningen",
      body: <>Lägg till hidden fields i Fluent Forms för <code className="font-mono text-[11px]">first_landing_page</code>, <code className="font-mono text-[11px]">utm_*</code>, <code className="font-mono text-[11px]">gclid</code>, <code className="font-mono text-[11px]">gbraid</code> och <code className="font-mono text-[11px]">referrer</code>.</>
    });
    if(attribution.topLanding.length){
      const top = attribution.topLanding[0];
      // count how many of these landed via Google Ads
      const adsCount = leads.filter(l => (l.first_landing_page === top.page) && l.kalla_kategori === "Google Ads").length;
      if(adsCount > 0){
        out.push({
          tone: "info",
          title: "Bästa landningssida",
          body: <><code className="font-mono text-[11px]">{top.page}</code> har flest spårade {adsCount > 0 ? "Google Ads-" : ""}leads ({top.leads} st totalt).</>
        });
      }
    }

    return out;
  }, [channelStats, tjanstStats, weekdayStats, hourStats, seNoCompare, attribution, leads]);

  return (
    <>
      <Topbar
        title={`Analys för ${period.label}`}
        subtitle={period.isCalendarMonth
          ? "Automatiska insikter och jämförelser för vald månad. Använd dem som diskussionsunderlag med Pineberry."
          : `Automatiska insikter för vald period (${period.days} dagar). Budget och CPL är prorerade från månadskostnader.`}
        market={market}
        periodLabel={period.label}
      />

      {/* Insights */}
      <div className="grid grid-cols-3 gap-3 mb-6">
        {insights.slice(0,6).map((ins,i) => (
          <div key={i} className="bg-white border border-paper-200 rounded-xl p-4 flex gap-3">
            <div className={`shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-[12px] font-medium
              ${ins.tone==="good" ? "bg-accent-soft text-accent-ink"
              : ins.tone==="warn" ? "bg-amber-50 text-amber-800"
              : "bg-sky-50 text-sky-800"}`}>
              {ins.tone === "good" ? "✓" : ins.tone === "warn" ? "!" : "i"}
            </div>
            <div className="flex-1">
              <div className="eyebrow text-ink-500 mb-1">{ins.title}</div>
              <div className="text-[13.5px] text-ink-800 leading-snug">{ins.body}</div>
            </div>
          </div>
        ))}
      </div>

      {/* SE vs NO Comparison (only in BOTH mode) */}
      {market === "BOTH" && seNoCompare && (
        <Card title="EasyTull SE vs EasyToll NO" subtitle="Direktjämförelse av nyckeltal" className="mb-5">
          <div className="grid grid-cols-4 gap-4 mt-1">
            <CompareRow label="Leads" se={fmtNum(seNoCompare.SE.leads)} no={fmtNum(seNoCompare.NO.leads)} winner={seNoCompare.SE.leads >= seNoCompare.NO.leads ? "SE" : "NO"}/>
            <CompareRow label="Konvertering" se={fmtPct(seNoCompare.SE.conv)} no={fmtPct(seNoCompare.NO.conv)} winner={seNoCompare.SE.conv >= seNoCompare.NO.conv ? "SE" : "NO"}/>
            <CompareRow label="CPL" se={fmtMoney(seNoCompare.SE.cpl, "SE")} no={fmtMoney(seNoCompare.NO.cpl, "NO")} winner={seNoCompare.SE.cpl <= seNoCompare.NO.cpl ? "SE" : "NO"} lowerBetter/>
            <CompareRow label="ROI" se={fmtPct(seNoCompare.SE.roi, 0)} no={fmtPct(seNoCompare.NO.roi, 0)} winner={seNoCompare.SE.roi >= seNoCompare.NO.roi ? "SE" : "NO"}/>
          </div>
        </Card>
      )}

      {/* ============= Attribution & spårningskvalitet ============= */}
      <Card title="Attribution & spårningskvalitet" subtitle="Leads per källa, säkerhetsnivå och de sidor som driver mest trafik" className="mb-5">
        <div className="grid grid-cols-12 gap-5 mt-1">
          {/* Per source */}
          <div className="col-span-7">
            <div className="eyebrow text-ink-500 mb-3">Leads per källa</div>
            <div className="space-y-2.5">
              {attribution.sources.map(s => {
                const max = Math.max(...attribution.sources.map(x => x.leads), 1);
                const cur = market === "BOTH" ? "kr" : (market === "NO" ? "NOK" : "SEK");
                return (
                  <div key={s.kalla} className="grid grid-cols-[170px_1fr_auto_auto_auto] items-center gap-3 text-[13px]">
                    <SourceBadge source={s.kalla} size="sm"/>
                    <div className="h-1.5 bg-paper-100 rounded-full overflow-hidden">
                      <div className="h-full rounded-full" style={{
                        width: `${(s.leads/max)*100}%`,
                        background: SOURCE_STYLE[s.kalla] ? SOURCE_STYLE[s.kalla].dot.replace("bg-[","").replace("]","") : "#3a4150"
                      }}></div>
                    </div>
                    <span className="num text-ink-800 w-10 text-right">{s.leads}</span>
                    <span className="num text-ink-500 w-16 text-right">{fmtPct(s.convRate, 0)}</span>
                    <span className="num text-ink-700 w-28 text-right">{fmtNum(s.intakt)} <span className="text-[10px] text-ink-400">{cur}</span></span>
                  </div>
                );
              })}
              <div className="grid grid-cols-[170px_1fr_auto_auto_auto] items-center gap-3 text-[10px] text-ink-400 uppercase tracking-wider pt-1.5 border-t border-paper-200">
                <span>Källa</span><span></span>
                <span className="w-10 text-right">Leads</span>
                <span className="w-16 text-right">Konv.</span>
                <span className="w-28 text-right">Intäkt</span>
              </div>
            </div>
          </div>

          {/* Confidence breakdown */}
          <div className="col-span-5">
            <div className="eyebrow text-ink-500 mb-3">Säkerhetsnivå</div>
            <div className="space-y-2">
              {["Hög","Medel","Låg","Okänd"].map(level => {
                const n = attribution.confidence[level] || 0;
                const pct = leads.length ? (n/leads.length)*100 : 0;
                return (
                  <div key={level} className="flex items-center gap-3">
                    <ConfidenceBadge level={level} size="sm"/>
                    <div className="flex-1 h-1.5 bg-paper-100 rounded-full overflow-hidden">
                      <div className="h-full rounded-full" style={{
                        width: `${pct}%`,
                        background: level==="Hög"?"#3a8a5a":level==="Medel"?"#d6a44e":level==="Låg"?"#c25a5f":"#c4cad3"
                      }}></div>
                    </div>
                    <span className="num text-ink-800 w-10 text-right">{n}</span>
                    <span className="num text-ink-500 w-12 text-right">{fmtPct(pct, 0)}</span>
                  </div>
                );
              })}
            </div>
            <div className="mt-4 pt-3 border-t border-paper-200 text-[12px] text-ink-600 leading-snug">
              <strong className="num text-ink-900">{attribution.confidence["Hög"] || 0}</strong> av {leads.length} leads har <strong>säker</strong> attribution
              ({fmtPct(leads.length ? ((attribution.confidence["Hög"]||0)/leads.length)*100 : 0, 0)}).
            </div>
          </div>

          {/* Top landing pages */}
          <div className="col-span-6 border-t border-paper-200 pt-4">
            <div className="eyebrow text-ink-500 mb-3">Toppsidor — first landing</div>
            <div className="space-y-1.5">
              {attribution.topLanding.map(p => {
                const max = Math.max(...attribution.topLanding.map(x => x.leads), 1);
                return (
                  <div key={p.page} className="flex items-center gap-3 text-[13px]">
                    <code className="font-mono text-[12px] text-ink-700 bg-paper-100 px-1.5 py-0.5 rounded truncate max-w-[280px]" title={p.page}>{p.page}</code>
                    <div className="flex-1 h-1.5 bg-paper-100 rounded-full overflow-hidden">
                      <div className="h-full rounded-full bg-accent" style={{ width:`${(p.leads/max)*100}%` }}></div>
                    </div>
                    <span className="num text-ink-700 w-8 text-right">{p.leads}</span>
                  </div>
                );
              })}
              {attribution.topLanding.length === 0 && (
                <div className="text-[12px] italic text-ink-400">Ingen first_landing_page spårad denna månad.</div>
              )}
            </div>
          </div>

          {/* Top form pages */}
          <div className="col-span-6 border-t border-paper-200 pt-4">
            <div className="eyebrow text-ink-500 mb-3">Toppsidor — formulär</div>
            <div className="space-y-1.5">
              {attribution.topForm.map(p => {
                const max = Math.max(...attribution.topForm.map(x => x.leads), 1);
                return (
                  <div key={p.page} className="flex items-center gap-3 text-[13px]">
                    <code className="font-mono text-[12px] text-ink-700 bg-paper-100 px-1.5 py-0.5 rounded truncate max-w-[280px]" title={p.page}>{p.page}</code>
                    <div className="flex-1 h-1.5 bg-paper-100 rounded-full overflow-hidden">
                      <div className="h-full rounded-full bg-ink-600" style={{ width:`${(p.leads/max)*100}%` }}></div>
                    </div>
                    <span className="num text-ink-700 w-8 text-right">{p.leads}</span>
                  </div>
                );
              })}
              {attribution.topForm.length === 0 && (
                <div className="text-[12px] italic text-ink-400">Inga formulärsidor spårade.</div>
              )}
            </div>
          </div>
        </div>
      </Card>

      {/* Per channel table */}
      <Card title="Prestanda per kanal" subtitle="CPL, konvertering och enkel ROI" className="mb-5">
        <table className="w-full text-sm">
          <thead>
            <tr className="text-left text-ink-500 text-[11px] tracking-wider uppercase border-b border-paper-200">
              <th className="py-2 font-medium">Kanal</th>
              {market === "BOTH" && <th className="py-2 font-medium">Marknad</th>}
              <th className="py-2 font-medium text-right">Leads</th>
              <th className="py-2 font-medium text-right">Konvertering</th>
              <th className="py-2 font-medium text-right">Spend</th>
              <th className="py-2 font-medium text-right">CPL</th>
              <th className="py-2 font-medium text-right">Intäkt</th>
              <th className="py-2 font-medium text-right">ROI</th>
            </tr>
          </thead>
          <tbody>
            {channelStats.map(c => (
              <tr key={c.kanal + c.land} className="border-b border-paper-100 last:border-0">
                <td className="py-2.5 text-ink-800">{c.kanal}</td>
                {market === "BOTH" && <td className="py-2.5"><MarketTag market={c.land}/></td>}
                <td className="py-2.5 text-right num">{c.leads}</td>
                <td className="py-2.5 text-right num">{fmtPct(c.convRate)}</td>
                <td className="py-2.5 text-right num text-ink-500">{c.spend ? fmtMoney(c.spend, c.land) : <span className="text-ink-400">—</span>}</td>
                <td className="py-2.5 text-right num">{c.spend ? fmtMoney(c.cpl, c.land) : <span className="text-ink-400">—</span>}</td>
                <td className="py-2.5 text-right num">{fmtMoney(c.intakt, c.land)}</td>
                <td className={`py-2.5 text-right num ${c.roi >= 0 ? "text-accent-ink" : "text-rose-700"}`}>
                  {c.spend ? fmtPct(c.roi, 0) : <span className="text-ink-400">—</span>}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>

      {/* Tjänst + Tid */}
      <div className="grid grid-cols-2 gap-5 mb-5">
        <Card title="Mest efterfrågade tjänster" subtitle="Antal leads per tjänstetyp">
          <div className="space-y-2.5 mt-1">
            {tjanstStats.map(t => {
              const max = Math.max(...tjanstStats.map(s=>s.leads), 1);
              return (
                <div key={t.tjanst}>
                  <div className="flex justify-between text-[13px] mb-1">
                    <span className="text-ink-800">{t.tjanst}</span>
                    <span className="num text-ink-500">{t.leads}</span>
                  </div>
                  <div className="h-1.5 bg-paper-100 rounded-full overflow-hidden">
                    <div className="h-full rounded-full bg-accent" style={{ width: `${(t.leads/max)*100}%` }}></div>
                  </div>
                </div>
              );
            })}
          </div>
        </Card>
        <Card title="Tid på dagen" subtitle="När når kunderna ut?">
          <div className="h-[180px] -ml-2 mt-1">
            <ResponsiveContainer>
              <BarChart data={hourStats}>
                <CartesianGrid stroke="#ecebe4" strokeDasharray="3 3" vertical={false}/>
                <XAxis dataKey="tid" axisLine={false} tickLine={false}/>
                <YAxis axisLine={false} tickLine={false} width={28}/>
                <Tooltip content={<ChartTooltip/>}/>
                <Bar dataKey="leads" fill={COLOR_ACCENT} radius={[3,3,0,0]} maxBarSize={48}/>
              </BarChart>
            </ResponsiveContainer>
          </div>
        </Card>
      </div>

      <Card title="Leads per veckodag" subtitle="Identifiera mönster över veckan">
        <div className="h-[200px] -ml-2 mt-1">
          <ResponsiveContainer>
            <BarChart data={weekdayStats}>
              <CartesianGrid stroke="#ecebe4" strokeDasharray="3 3" vertical={false}/>
              <XAxis dataKey="dag" axisLine={false} tickLine={false}/>
              <YAxis axisLine={false} tickLine={false} width={28}/>
              <Tooltip content={<ChartTooltip/>}/>
              <Bar dataKey="leads" radius={[3,3,0,0]} maxBarSize={48}>
                {weekdayStats.map((d,i) => {
                  const max = Math.max(...weekdayStats.map(x=>x.leads), 1);
                  const isTop = d.leads === max;
                  return <Cell key={i} fill={isTop ? COLOR_ACCENT : "#c4cad3"}/>;
                })}
              </Bar>
            </BarChart>
          </ResponsiveContainer>
        </div>
      </Card>
    </>
  );
}

function CompareRow({ label, se, no, winner, lowerBetter }){
  return (
    <div className="bg-paper-50 border border-paper-200 rounded-lg p-4">
      <div className="eyebrow text-ink-500 mb-2">{label}</div>
      <div className="space-y-2">
        <div className={`flex items-center gap-2 ${winner==="SE" ? "" : "opacity-50"}`}>
          <FlagSE size={11}/>
          <span className="display num text-[18px] text-ink-900">{se}</span>
          {winner==="SE" && <span className="text-[10px] text-accent-ink ml-auto px-1.5 py-0.5 bg-accent-soft rounded-full">Bäst</span>}
        </div>
        <div className={`flex items-center gap-2 ${winner==="NO" ? "" : "opacity-50"}`}>
          <FlagNO size={11}/>
          <span className="display num text-[18px] text-ink-900">{no}</span>
          {winner==="NO" && <span className="text-[10px] text-accent-ink ml-auto px-1.5 py-0.5 bg-accent-soft rounded-full">Bäst</span>}
        </div>
      </div>
    </div>
  );
}

// =============== INSTÄLLNINGAR ===================================
function InstallningarView({ market, period, mal, setMal, valuta, setValuta, users, setUsers }){
  const [inviteOpen, setInviteOpen] = useState(false);
  const [inviteEmail, setInviteEmail] = useState("");
  const [inviteRole, setInviteRole] = useState("Redaktör");
  const [inviteStatus, setInviteStatus] = useState("");
  const inviteRoles = ["Redaktör", "Byrå"];

  async function sendInvite(){
    const email = inviteEmail.trim().toLowerCase();
    if(!email) return;
    if(users.some(u => u.email === email)){
      setInviteStatus("Användaren finns redan.");
      return;
    }
    setInviteStatus("Skickar inbjudan...");
    try {
      await window.EASYTULL_BACKEND?.sendInvite(email);
      const nextUser = userFromEmail(email, inviteRole);
      setUsers(arr => [...arr, nextUser]);
      setInviteStatus("Inbjudan skickad.");
      setInviteEmail("");
      setInviteRole("Redaktör");
      setInviteOpen(false);
    } catch(err) {
      setInviteStatus(err.message || "Kunde inte skicka inbjudan.");
    }
  }

  return (
    <>
      <Topbar
        title="Inställningar"
        subtitle="Hantera användare, mål per månad och visningsvaluta per marknad."
        market={market}
        periodLabel={period.label}
      />

      {/* Goals */}
      <Card title="Mål per månad" subtitle="Sätt målvärden – KPI-kort jämför sedan utfall mot mål." className="mb-5">
        <div className="grid grid-cols-2 gap-4 mt-1">
          <GoalEditor market="SE" mal={mal.SE} cur={valuta.SE} onChange={p=>setMal(s=>({ ...s, SE: { ...s.SE, ...p }}))}/>
          <GoalEditor market="NO" mal={mal.NO} cur={valuta.NO} onChange={p=>setMal(s=>({ ...s, NO: { ...s.NO, ...p }}))}/>
        </div>
      </Card>

      {/* Currency */}
      <Card title="Visningsvaluta" subtitle="Per marknad" className="mb-5">
        <div className="grid grid-cols-2 gap-4 mt-1">
          <CurrencyPick market="SE" value={valuta.SE} onChange={v=>setValuta(s=>({ ...s, SE: v }))}/>
          <CurrencyPick market="NO" value={valuta.NO} onChange={v=>setValuta(s=>({ ...s, NO: v }))}/>
        </div>
      </Card>

      {/* Users */}
      <Card title="Användare" subtitle="Admin och inbjudna användare" right={<Btn size="sm" variant="primary" onClick={()=>{ setInviteOpen(true); setInviteStatus(""); }}>+ Bjud in</Btn>}>
        {inviteOpen && (
          <div className="mb-5 bg-paper-50 border border-paper-200 rounded-xl p-4">
            <div className="grid grid-cols-[1fr_180px_auto] gap-3 items-end">
              <label>
                <span className="eyebrow text-ink-500 block mb-1.5">E-post</span>
                <input
                  type="email"
                  value={inviteEmail}
                  onChange={e=>setInviteEmail(e.target.value)}
                  placeholder="namn@foretag.se"
                  className="w-full bg-white border border-paper-200 rounded-lg px-3 py-2.5 text-sm outline-none focus:border-ink-700"
                />
              </label>
              <label>
                <span className="eyebrow text-ink-500 block mb-1.5">Behörighet</span>
                <select value={inviteRole} onChange={e=>setInviteRole(e.target.value)} className="bare w-full bg-white border border-paper-200 rounded-lg px-3 py-2.5 text-sm outline-none focus:border-ink-700">
                  {inviteRoles.map(role => <option key={role} value={role}>{role}</option>)}
                </select>
              </label>
              <div className="flex gap-2">
                <Btn size="sm" variant="ghost" onClick={()=>setInviteOpen(false)}>Avbryt</Btn>
                <Btn size="sm" variant="primary" onClick={sendInvite}>Skicka</Btn>
              </div>
            </div>
            <p className="text-[12px] text-ink-500 mt-3">
              Inbjudna användare kan ändra dashboardens fält, men får inte tillgång till Inställningar eller Privat ekonomi.
            </p>
            {inviteStatus && <div className="text-[12px] text-ink-700 mt-2">{inviteStatus}</div>}
          </div>
        )}
        <table className="w-full text-sm">
          <thead>
            <tr className="text-left text-ink-500 text-[11px] tracking-wider uppercase border-b border-paper-200">
              <th className="py-2 font-medium">Namn</th>
              <th className="py-2 font-medium">Roll</th>
              <th className="py-2 font-medium">E-post</th>
              <th className="py-2 font-medium">Senast inloggad</th>
              <th className="py-2 font-medium">Status</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {users.map(u => (
              <tr key={u.email} className="border-b border-paper-100 last:border-0">
                <td className="py-3 text-ink-900 flex items-center gap-2.5">
                  <span className="w-7 h-7 rounded-full bg-paper-200 flex items-center justify-center text-ink-700 text-xs display">{u.namn.charAt(0)}</span>
                  {u.namn}
                </td>
                <td className="py-3 text-ink-700">{u.roll}</td>
                <td className="py-3 text-ink-500 num">{u.email}</td>
                <td className="py-3 text-ink-500">{u.sistInne}</td>
                <td className="py-3">
                  <span className="inline-flex items-center gap-1.5 text-[12px] px-2 py-0.5 rounded-full bg-accent-soft text-accent-ink">
                    <span className="w-1.5 h-1.5 rounded-full bg-accent"></span>Aktiv
                  </span>
                </td>
                <td className="py-3 text-right">
                  {u.rolltyp !== "Admin" && (
                    <button
                      onClick={()=>setUsers(arr => arr.filter(x => x.email !== u.email))}
                      className="text-xs text-rose-700 hover:text-rose-900"
                    >
                      Ta bort
                    </button>
                  )}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </>
  );
}

function GoalEditor({ market, mal, cur, onChange }){
  return (
    <div className="bg-paper-50 border border-paper-200 rounded-lg p-4">
      <div className="flex items-center gap-2 mb-3">
        {market==="SE" ? <FlagSE/> : <FlagNO/>}
        <span className="text-[14px] text-ink-900 font-medium">{market === "SE" ? "EasyTull · Sverige" : "EasyToll · Norge"}</span>
      </div>
      <div className="space-y-2.5">
        <GoalInput label={`Budget (${cur})`} value={mal.budget} onChange={v=>onChange({budget:v})}/>
        <GoalInput label="Antal leads" value={mal.leads} onChange={v=>onChange({leads:v})}/>
        <GoalInput label="Konvertering (%)" value={mal.konvertering} onChange={v=>onChange({konvertering:v})}/>
      </div>
    </div>
  );
}
function GoalInput({ label, value, onChange }){
  return (
    <label className="flex items-center justify-between gap-3">
      <span className="text-[13px] text-ink-700">{label}</span>
      <input type="number" value={value} onChange={e=>onChange(Number(e.target.value))}
        className="w-32 bg-white border border-paper-200 rounded-md px-2.5 py-1.5 text-sm text-right num focus:outline-none focus:border-ink-600"/>
    </label>
  );
}
function CurrencyPick({ market, value, onChange }){
  const options = market === "SE" ? ["SEK","NOK","EUR"] : ["NOK","SEK","EUR"];
  return (
    <div className="bg-paper-50 border border-paper-200 rounded-lg p-4">
      <div className="flex items-center gap-2 mb-3">
        {market==="SE" ? <FlagSE/> : <FlagNO/>}
        <span className="text-[14px] text-ink-900 font-medium">{market === "SE" ? "Sverige" : "Norge"}</span>
      </div>
      <div className="flex gap-2">
        {options.map(o => (
          <button key={o} onClick={()=>onChange(o)}
            className={`flex-1 px-3 py-2 rounded-md text-sm border transition
              ${value===o ? "bg-ink-900 text-paper-50 border-ink-900" : "bg-white text-ink-700 border-paper-200 hover:border-ink-600"}`}
          >{o}</button>
        ))}
      </div>
    </div>
  );
}

// expose
Object.assign(window, { OversiktView, LeadsView, BudgetView, AnalysView, InstallningarView, FilterSelect });
