import React, { useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import { Activity, AlertTriangle, ArrowRight, BarChart3, BellRing, BookOpen, BrainCircuit, CalendarDays, CheckCircle2, ChevronRight, CircleDollarSign, FileText, Gauge, LayoutDashboard, LogOut, Menu, Plus, RefreshCw, Save, Settings, ShieldCheck, Sparkles, Target, WalletCards, PackageCheck, X, XCircle } from "lucide-react";
import { supabase } from "./lib/supabaseClient.js";

const CONTRACT={name:"CAP_COMMAND_CENTER",version:"1.0.0",status:"frozen"};
const SIGNAL_CONTRACT={name:"CAP_SIGNAL_CENTER",version:"1.0.0",status:"frozen"};
const AI_CONTRACT={name:"CAP_AI_BRIEF",version:"1.0.0",status:"deterministic_foundation"};
const NAV=[["Command Center",LayoutDashboard,"command"],["Sellability Gate",ShieldCheck,"sellability"],["Founding V10",PackageCheck,"founding"],["Attention Center",AlertTriangle,"attention"],["Signal Center",BellRing,"signals"],["CAP AI Assistant",BrainCircuit,"ai"],["Agenda & Missions",CalendarDays,"agenda"],["Finances",CircleDollarSign,"finance"],["Livre de caisse",BookOpen,"cashbook"],["Objectifs & KPI",Target,"kpi"],["Documents",FileText,"documents"],["Paramètres",Settings,"settings"]];
const cls=(...x)=>x.filter(Boolean).join(" "); const arr=v=>Array.isArray(v)?v:[];
const money=(v,c="EUR")=>v==null?"—":new Intl.NumberFormat("fr-BE",{style:"currency",currency:c||"EUR",maximumFractionDigits:2}).format(Number(v));
const num=v=>v==null?"—":new Intl.NumberFormat("fr-BE",{maximumFractionDigits:2}).format(Number(v));
const date=v=>{if(!v)return"—";const d=new Date(v);return Number.isNaN(d.getTime())?String(v):new Intl.DateTimeFormat("fr-BE",{day:"2-digit",month:"short",year:"numeric"}).format(d)};
const datetime=v=>{if(!v)return"—";const d=new Date(v);return Number.isNaN(d.getTime())?String(v):new Intl.DateTimeFormat("fr-BE",{day:"2-digit",month:"short",hour:"2-digit",minute:"2-digit"}).format(d)};
function Card({children,className=""}){return <section className={cls("rounded-2xl border border-white/10 bg-white/[0.035] shadow-[0_18px_50px_rgba(0,0,0,.18)]",className)}>{children}</section>}
function Title({icon:Icon,eyebrow,title,right}){return <div className="flex items-start justify-between gap-4 border-b border-white/8 px-5 py-4"><div className="flex items-start gap-3">{Icon&&<div className="rounded-xl border border-white/10 bg-white/5 p-2"><Icon size={17} className="text-slate-300"/></div>}<div><div className="text-[10px] font-semibold uppercase tracking-[.22em] text-slate-500">{eyebrow}</div><h2 className="mt-1 text-sm font-semibold text-slate-100">{title}</h2></div></div>{right}</div>}
function Empty({text,sub}){return <div className="px-5 py-8 text-center"><div className="text-sm text-slate-500">{text}</div>{sub&&<div className="mt-1 text-[10px] text-slate-700">{sub}</div>}</div>}
function Severity({severity}){const m={critical:["CRITIQUE","border-red-400/25 bg-red-400/10 text-red-200"],warning:["ATTENTION","border-amber-300/25 bg-amber-300/10 text-amber-100"],info:["INFO","border-sky-300/20 bg-sky-300/10 text-sky-100"]};const [l,s]=m[severity]||[String(severity||"INFO").toUpperCase(),"border-white/10 bg-white/5 text-slate-300"];return <span className={cls("rounded-full border px-2 py-1 text-[9px] font-bold tracking-[.14em]",s)}>{l}</span>}
function Btn({children,onClick,type="button",disabled=false,primary=false}){return <button type={type} onClick={onClick} disabled={disabled} className={cls("rounded-xl px-3 py-2 text-xs font-semibold disabled:opacity-50",primary?"bg-slate-100 text-slate-950":"border border-white/10 text-slate-300 hover:bg-white/5")}>{children}</button>}
function Input(p){return <input {...p} className={cls("w-full rounded-xl border border-white/10 bg-black/20 px-3 py-2.5 text-sm text-slate-100 outline-none focus:border-white/25",p.className||"")}/>}
function Select(p){return <select {...p} className="w-full rounded-xl border border-white/10 bg-[#111720] px-3 py-2.5 text-sm text-slate-100 outline-none">{p.children}</select>}
function Field({label,children}){return <label className="block"><span className="mb-1.5 block text-[10px] uppercase tracking-[.14em] text-slate-600">{label}</span>{children}</label>}
function Notice({error,ok}){return <>{error&&<div className="rounded-xl border border-red-400/20 bg-red-400/10 px-3 py-2 text-xs text-red-200">{error}</div>}{ok&&<div className="rounded-xl border border-emerald-400/20 bg-emerald-400/10 px-3 py-2 text-xs text-emerald-200">{ok}</div>}</>}

function Login({onReady}){const[email,setEmail]=useState("");const[token,setToken]=useState("");const[stage,setStage]=useState("email");const[busy,setBusy]=useState(false);const[msg,setMsg]=useState("");const[error,setError]=useState("");async function send(e){e.preventDefault();setBusy(true);setError("");const{error}=await supabase.auth.signInWithOtp({email:email.trim(),options:{shouldCreateUser:false}});setBusy(false);if(error)return setError(error.message);setStage("otp");setMsg("Code envoyé. Consultez votre boîte mail.")}async function verify(e){e.preventDefault();setBusy(true);setError("");const{data,error}=await supabase.auth.verifyOtp({email:email.trim(),token:token.trim(),type:"email"});setBusy(false);if(error)return setError(error.message);if(data?.session)onReady(data.session)}return <div className="min-h-screen bg-[#0d1117] text-white flex items-center justify-center px-5"><div className="w-full max-w-md"><div className="mb-8"><div className="text-xs font-bold tracking-[.24em] text-slate-500">CAP</div><h1 className="mt-2 text-3xl font-semibold">Business Pro Executive V10</h1><p className="mt-3 text-sm text-slate-400">Accès sécurisé au cockpit opérationnel.</p></div><Card className="p-6"><form onSubmit={stage==="email"?send:verify} className="space-y-4"><Field label="E-mail"><Input type="email" required disabled={stage==="otp"} value={email} onChange={e=>setEmail(e.target.value)}/></Field>{stage==="otp"&&<Field label="Code à 6 chiffres"><Input inputMode="numeric" autoComplete="one-time-code" required value={token} onChange={e=>setToken(e.target.value.replace(/\D/g,"").slice(0,6))}/></Field>}<Notice error={error} ok={msg}/><Btn type="submit" primary disabled={busy}>{busy?"Traitement…":stage==="email"?"Recevoir mon code":"Ouvrir mon cockpit"}</Btn></form></Card><div className="mt-5 text-center text-[10px] tracking-[.15em] text-slate-600">CAP BUSINESS PRO EXECUTIVE V10 · BUILD 008</div></div></div>}

function Command({data,onRefresh,refreshing}){const h=data?.header||{},c=data?.command||{},p=data?.performance||{},a=data?.attention||{},f=h.focus||{},missions=arr(c.missions),agenda=arr(c.agenda),signals=arr(c.signals),kpis=arr(p.kpis),finance=p.finance||{},counts=a.counts||{};return <><div className="mb-6 grid gap-4 xl:grid-cols-[1.35fr_.65fr]"><Card className="p-6"><div className="text-[10px] uppercase tracking-[.22em] text-slate-500">Direction actuelle</div><h1 className="mt-3 text-3xl font-semibold">{f.focus_90_days||f.direction||"Aucun focus défini"}</h1><div className="mt-5 flex gap-3 rounded-xl border border-white/8 bg-black/15 p-4"><ArrowRight size={17} className="mt-1 text-slate-500"/><div><div className="text-[10px] uppercase tracking-[.18em] text-slate-600">Prochaine victoire</div><div className="mt-1 text-sm text-slate-300">{f.next_win||"Aucune prochaine victoire définie."}</div></div></div></Card><Card className="p-5"><div className="flex justify-between"><div><div className="text-[10px] uppercase tracking-[.22em] text-slate-500">Attention</div><div className="mt-2 text-lg font-semibold">Vue immédiate</div></div><Gauge size={22} className="text-slate-500"/></div><div className="mt-5 grid grid-cols-2 gap-3">{[["Missions ouvertes",counts.open_missions],["Agenda · 7 jours",counts.agenda_next_7d],["Signaux ouverts",counts.open_signals],["Notifications",counts.unread_notifications]].map(([l,v])=><div key={l} className="rounded-xl border border-white/8 bg-black/15 p-3"><div className="text-xl font-semibold">{v??"—"}</div><div className="mt-1 text-[10px] text-slate-600">{l}</div></div>)}</div></Card></div><div className="grid gap-5 xl:grid-cols-12"><div className="space-y-5 xl:col-span-7"><Card><Title icon={Target} eyebrow="Command" title="Missions prioritaires"/><div className="divide-y divide-white/8">{missions.length?missions.map((m,i)=><div key={m.id||i} className="px-5 py-4"><div className="text-sm font-medium">{m.title}</div><div className="mt-2 text-[10px] text-slate-500">Priorité {m.priority} · {m.status} {m.due_at&&`· ${datetime(m.due_at)}`}</div></div>):<Empty text="Aucune mission prioritaire."/>}</div></Card><Card><Title icon={CalendarDays} eyebrow="Command" title="Agenda · 7 prochains jours"/><div className="divide-y divide-white/8">{agenda.length?agenda.map(x=><div key={x.id} className="px-5 py-4"><div className="text-sm">{x.action}</div><div className="mt-1 text-[10px] text-slate-600">{x.date} · {String(x.time||"").slice(0,5)} · {x.duration_minutes} min</div></div>):<Empty text="Agenda vide pour les 7 prochains jours." sub="Aucun événement fictif n’est affiché."/>}</div></Card><Card><Title icon={AlertTriangle} eyebrow="Command" title="Signaux à traiter"/><div className="divide-y divide-white/8">{signals.length?signals.map(s=><div key={s.id} className="flex justify-between gap-4 px-5 py-4"><div><div className="text-sm">{s.title}</div>{s.body&&<div className="mt-1 text-xs text-slate-500">{s.body}</div>}</div><Severity severity={s.severity}/></div>):<Empty text="Aucun signal ouvert."/>}</div></Card></div><div className="space-y-5 xl:col-span-5"><Card><Title icon={WalletCards} eyebrow="Performance" title="Finances · 30 jours"/><div className="grid grid-cols-2 gap-px bg-white/8">{[["Rentrées",finance.income_30d],["Sorties",finance.expense_30d],["À échéance",finance.due_30d],["En retard",finance.overdue_count]].map(([l,v])=><div key={l} className="bg-[#0d1117] p-5"><div className="text-[10px] uppercase text-slate-600">{l}</div><div className="mt-2 text-xl font-semibold">{num(v)}</div></div>)}</div><div className="px-5 py-3 text-[10px] text-slate-600">Le contrat Command Center V1.0 ne fournit pas la devise.</div></Card><Card><Title icon={BarChart3} eyebrow="Performance" title="Objectifs & KPI"/><div className="divide-y divide-white/8">{kpis.map(k=><div key={k.id} className="flex justify-between px-5 py-4"><div><div className="text-sm">{k.label}</div><div className="text-[10px] text-slate-600">{k.unit||"indicateur"}</div></div><div className="text-right"><b>{k.value??"—"}</b><div className="text-[10px] text-slate-600">cible {k.target??"—"}</div></div></div>)}</div></Card><Card className="p-5"><div className="flex gap-3"><Activity size={18} className="text-slate-500"/><div><div className="text-xs font-semibold">CAP AI · fondation prête</div><p className="mt-2 text-xs text-slate-600">Aucune recommandation IA fictive. Les données affichées viennent du backend autorisé.</p></div></div></Card></div></div></>}

function AgendaPage({uid,onChanged}){const[missions,setM]=useState([]),[agenda,setA]=useState([]),[error,setError]=useState(""),[ok,setOk]=useState("");const[fm,setFm]=useState({title:"",priority:"2",due_at:""});const[fa,setFa]=useState({action:"",planned_date:"",planned_time:"",duration_minutes:"30"});async function load(){setError("");const[m,a]=await Promise.all([supabase.from("missions").select("*").order("priority").order("due_at",{ascending:true}),supabase.from("agenda_items").select("*").order("planned_date").order("planned_time")]);if(m.error||a.error)return setError(m.error?.message||a.error?.message);setM(m.data||[]);setA(a.data||[])}useEffect(()=>{load()},[]);async function addMission(e){e.preventDefault();setError("");const{error}=await supabase.from("missions").insert({user_id:uid,title:fm.title.trim(),priority:Number(fm.priority),due_at:fm.due_at?new Date(fm.due_at).toISOString():null,mission_type:"action",status:"planned"});if(error)return setError(error.message);setFm({title:"",priority:"2",due_at:""});setOk("Mission enregistrée.");await load();onChanged()}async function addAgenda(e){e.preventDefault();const{error}=await supabase.from("agenda_items").insert({user_id:uid,action:fa.action.trim(),planned_date:fa.planned_date,planned_time:fa.planned_time,duration_minutes:Number(fa.duration_minutes),status:"planned"});if(error)return setError(error.message);setFa({action:"",planned_date:"",planned_time:"",duration_minutes:"30"});setOk("Moment Agenda enregistré.");await load();onChanged()}async function status(table,id,status){const{error}=await supabase.from(table).update({status}).eq("id",id);if(error)return setError(error.message);await load();onChanged()}return <div className="space-y-5"><Notice error={error} ok={ok}/><div className="grid gap-5 xl:grid-cols-2"><Card><Title icon={Plus} eyebrow="Action" title="Nouvelle mission"/><form onSubmit={addMission} className="grid gap-3 p-5"><Field label="Mission"><Input required value={fm.title} onChange={e=>setFm({...fm,title:e.target.value})}/></Field><div className="grid grid-cols-2 gap-3"><Field label="Priorité"><Select value={fm.priority} onChange={e=>setFm({...fm,priority:e.target.value})}><option value="1">1 · Haute</option><option value="2">2 · Normale</option><option value="3">3 · Basse</option></Select></Field><Field label="Échéance"><Input type="datetime-local" value={fm.due_at} onChange={e=>setFm({...fm,due_at:e.target.value})}/></Field></div><Btn type="submit" primary>Ajouter la mission</Btn></form></Card><Card><Title icon={Plus} eyebrow="Agenda" title="Nouveau moment"/><form onSubmit={addAgenda} className="grid gap-3 p-5"><Field label="Action"><Input required value={fa.action} onChange={e=>setFa({...fa,action:e.target.value})}/></Field><div className="grid grid-cols-3 gap-3"><Field label="Date"><Input type="date" required value={fa.planned_date} onChange={e=>setFa({...fa,planned_date:e.target.value})}/></Field><Field label="Heure"><Input type="time" step="900" required value={fa.planned_time} onChange={e=>setFa({...fa,planned_time:e.target.value})}/></Field><Field label="Minutes"><Input type="number" min="15" step="15" required value={fa.duration_minutes} onChange={e=>setFa({...fa,duration_minutes:e.target.value})}/></Field></div><Btn type="submit" primary>Ajouter à l’Agenda</Btn></form></Card></div><Card><Title icon={Target} eyebrow="Opérations" title="Missions"/><div className="divide-y divide-white/8">{missions.length?missions.map(m=><div key={m.id} className="flex flex-col gap-3 px-5 py-4 sm:flex-row sm:items-center"><div className="flex-1"><div className="text-sm">{m.title}</div><div className="mt-1 text-[10px] text-slate-600">P{m.priority} · {m.status} · {datetime(m.due_at)}</div></div><div className="flex gap-2">{m.status!=="done"&&<Btn onClick={()=>status("missions",m.id,"done")}>Terminer</Btn>}{m.status==="planned"&&<Btn onClick={()=>status("missions",m.id,"in_progress")}>Démarrer</Btn>}</div></div>):<Empty text="Aucune mission."/>}</div></Card><Card><Title icon={CalendarDays} eyebrow="Opérations" title="Agenda"/><div className="divide-y divide-white/8">{agenda.length?agenda.map(a=><div key={a.id} className="flex items-center gap-3 px-5 py-4"><div className="flex-1"><div className="text-sm">{a.action}</div><div className="mt-1 text-[10px] text-slate-600">{a.planned_date} · {String(a.planned_time).slice(0,5)} · {a.duration_minutes} min · {a.status}</div></div>{a.status==="planned"&&<Btn onClick={()=>status("agenda_items",a.id,"done")}>Fait</Btn>}</div>):<Empty text="Agenda vide."/>}</div></Card></div>}

function FinancePage({uid,onChanged}){const[tx,setTx]=useState([]),[ob,setOb]=useState([]),[error,setError]=useState(""),[ok,setOk]=useState("");const[f,setF]=useState({transaction_date:new Date().toISOString().slice(0,10),direction:"expense",amount:"",currency:"EUR",category:"",counterparty:"",description:""});const[o,setO]=useState({label:"",obligation_type:"expense",amount:"",due_date:""});async function load(){const[t,b]=await Promise.all([supabase.from("financial_transactions").select("*").order("transaction_date",{ascending:false}).limit(50),supabase.from("financial_obligations").select("*").order("due_date",{ascending:true})]);if(t.error||b.error)return setError(t.error?.message||b.error?.message);setTx(t.data||[]);setOb(b.data||[])}useEffect(()=>{load()},[]);async function add(e){e.preventDefault();const{error}=await supabase.from("financial_transactions").insert({...f,user_id:uid,amount:Number(f.amount),status:"confirmed",source:"manual"});if(error)return setError(error.message);setF({...f,amount:"",category:"",counterparty:"",description:""});setOk("Mouvement enregistré.");await load();onChanged()}async function addOb(e){e.preventDefault();const{error}=await supabase.from("financial_obligations").insert({user_id:uid,label:o.label.trim(),obligation_type:o.obligation_type,amount:o.amount?Number(o.amount):null,due_date:o.due_date||null,status:"open"});if(error)return setError(error.message);setO({label:"",obligation_type:"expense",amount:"",due_date:""});setOk("Échéance enregistrée.");await load();onChanged()}async function paid(id){const{error}=await supabase.from("financial_obligations").update({status:"paid"}).eq("id",id);if(error)return setError(error.message);await load();onChanged()}const income=tx.filter(x=>x.direction==="income").reduce((s,x)=>s+Number(x.amount),0),expense=tx.filter(x=>x.direction==="expense").reduce((s,x)=>s+Number(x.amount),0);return <div className="space-y-5"><Notice error={error} ok={ok}/><div className="grid gap-4 sm:grid-cols-2"><Card className="p-5"><div className="text-[10px] uppercase text-slate-600">Rentrées enregistrées</div><div className="mt-2 text-2xl font-semibold">{money(income)}</div></Card><Card className="p-5"><div className="text-[10px] uppercase text-slate-600">Sorties enregistrées</div><div className="mt-2 text-2xl font-semibold">{money(expense)}</div></Card></div><div className="grid gap-5 xl:grid-cols-2"><Card><Title icon={Plus} eyebrow="Finances" title="Ajouter un mouvement"/><form onSubmit={add} className="grid gap-3 p-5"><div className="grid grid-cols-2 gap-3"><Field label="Date"><Input type="date" required value={f.transaction_date} onChange={e=>setF({...f,transaction_date:e.target.value})}/></Field><Field label="Sens"><Select value={f.direction} onChange={e=>setF({...f,direction:e.target.value})}><option value="income">Rentrée</option><option value="expense">Sortie</option><option value="transfer">Transfert</option></Select></Field></div><div className="grid grid-cols-2 gap-3"><Field label="Montant"><Input type="number" min="0" step="0.01" required value={f.amount} onChange={e=>setF({...f,amount:e.target.value})}/></Field><Field label="Devise"><Input value={f.currency} onChange={e=>setF({...f,currency:e.target.value.toUpperCase().slice(0,3)})}/></Field></div><Field label="Catégorie"><Input value={f.category} onChange={e=>setF({...f,category:e.target.value})}/></Field><Field label="Tiers"><Input value={f.counterparty} onChange={e=>setF({...f,counterparty:e.target.value})}/></Field><Field label="Description"><Input value={f.description} onChange={e=>setF({...f,description:e.target.value})}/></Field><Btn type="submit" primary>Enregistrer</Btn></form></Card><Card><Title icon={Plus} eyebrow="Finances" title="Ajouter une échéance"/><form onSubmit={addOb} className="grid gap-3 p-5"><Field label="Libellé"><Input required value={o.label} onChange={e=>setO({...o,label:e.target.value})}/></Field><div className="grid grid-cols-2 gap-3"><Field label="Montant"><Input type="number" min="0" step="0.01" value={o.amount} onChange={e=>setO({...o,amount:e.target.value})}/></Field><Field label="Échéance"><Input type="date" value={o.due_date} onChange={e=>setO({...o,due_date:e.target.value})}/></Field></div><Btn type="submit" primary>Ajouter l’échéance</Btn></form><div className="divide-y divide-white/8 border-t border-white/8">{ob.map(x=><div key={x.id} className="flex items-center gap-3 px-5 py-4"><div className="flex-1"><div className="text-sm">{x.label}</div><div className="mt-1 text-[10px] text-slate-600">{x.amount!=null?num(x.amount):"montant non défini"} · {x.due_date||"sans date"} · {x.status}</div></div>{x.status!=="paid"&&<Btn onClick={()=>paid(x.id)}>Payée</Btn>}</div>)}</div></Card></div></div>}

function Cashbook({uid}){const[rows,setRows]=useState([]),[error,setError]=useState("");useEffect(()=>{supabase.from("financial_transactions").select("*").order("transaction_date",{ascending:false}).limit(100).then(({data,error})=>{if(error)setError(error.message);else setRows(data||[])})},[]);return <div className="space-y-5"><Notice error={error}/><Card><Title icon={BookOpen} eyebrow="Registre" title="Livre de caisse · mouvements confirmés"/><div className="overflow-x-auto"><table className="w-full min-w-[760px] text-left text-xs"><thead className="border-b border-white/8 text-slate-600"><tr>{["Date","Sens","Montant","Catégorie","Tiers","Description","Source"].map(x=><th key={x} className="px-4 py-3 font-medium">{x}</th>)}</tr></thead><tbody className="divide-y divide-white/8">{rows.map(r=><tr key={r.id}><td className="px-4 py-3">{r.transaction_date}</td><td className="px-4 py-3">{r.direction}</td><td className="px-4 py-3 font-semibold">{money(r.amount,r.currency)}</td><td className="px-4 py-3">{r.category||"—"}</td><td className="px-4 py-3">{r.counterparty||"—"}</td><td className="px-4 py-3">{r.description||"—"}</td><td className="px-4 py-3 text-slate-600">{r.source}</td></tr>)}</tbody></table>{!rows.length&&<Empty text="Aucun mouvement enregistré."/>}</div></Card></div>}

function KPIPage({uid,onChanged}){const[defs,setDefs]=useState([]),[vals,setVals]=useState([]),[error,setError]=useState(""),[ok,setOk]=useState("");const[f,setF]=useState({id:"",value:""});async function load(){const[d,v]=await Promise.all([supabase.from("kpi_definitions").select("*").order("label"),supabase.from("kpi_values").select("*").order("measured_at",{ascending:false})]);if(d.error||v.error)return setError(d.error?.message||v.error?.message);setDefs(d.data||[]);setVals(v.data||[])}useEffect(()=>{load()},[]);async function add(e){e.preventDefault();const{error}=await supabase.from("kpi_values").insert({user_id:uid,kpi_definition_id:f.id,value:Number(f.value),source:"manual"});if(error)return setError(error.message);setF({id:"",value:""});setOk("Mesure KPI enregistrée.");await load();onChanged()}return <div className="space-y-5"><Notice error={error} ok={ok}/><Card><Title icon={Plus} eyebrow="Performance" title="Enregistrer une mesure KPI"/><form onSubmit={add} className="grid gap-3 p-5 sm:grid-cols-[1fr_180px_auto]"><Select required value={f.id} onChange={e=>setF({...f,id:e.target.value})}><option value="">Choisir un KPI</option>{defs.map(d=><option key={d.id} value={d.id}>{d.label}</option>)}</Select><Input type="number" step="0.01" required placeholder="Valeur" value={f.value} onChange={e=>setF({...f,value:e.target.value})}/><Btn type="submit" primary>Enregistrer</Btn></form></Card><div className="grid gap-4 lg:grid-cols-3">{defs.map(d=>{const latest=vals.find(v=>v.kpi_definition_id===d.id);return <Card key={d.id} className="p-5"><div className="text-sm font-semibold">{d.label}</div><div className="mt-1 text-[10px] uppercase text-slate-600">{d.unit||"indicateur"}</div><div className="mt-5 flex items-end justify-between"><div><div className="text-3xl font-semibold">{latest?.value??"—"}</div><div className="mt-1 text-[10px] text-slate-600">{latest?datetime(latest.measured_at):"Aucune mesure"}</div></div><div className="text-right text-xs text-slate-500">cible<br/><b className="text-slate-300">{d.target_value??"—"}</b></div></div></Card>})}</div></div>}


function SellabilityGate(){
  const[data,setData]=useState(null),[busy,setBusy]=useState(false),[error,setError]=useState("");
  async function load(){setBusy(true);setError("");const{data:p,error:e}=await supabase.rpc("cap_get_my_sellability_gate_v1");setBusy(false);if(e)return setError(e.message);if(p?.contract!=="sellability-gate-v1")return setError("Contrat Sellability Gate incompatible.");setData(p)}
  useEffect(()=>{load()},[]);
  const checks=arr(data?.checks),m=data?.metrics||{},sellable=data?.status==="sellable";
  const blocker={technical_proof:"Preuve technique",sellable_product:"Produit vendable",revenue_offer:"Offre activable"}[data?.next_blocker]||"Aucun bloqueur";
  return <div className="space-y-5"><Notice error={error}/><Card className="p-6"><div className="flex flex-wrap items-start justify-between gap-4"><div><div className="text-[10px] font-semibold uppercase tracking-[.22em] text-slate-500">GO-TO-MARKET GATE</div><h1 className="mt-2 text-3xl font-semibold">{sellable?"V10 VENDABLE":"PAS ENCORE VENDABLE"}</h1><p className="mt-3 max-w-2xl text-sm text-slate-400">CAP sépare la preuve technique de la preuve commerciale. Le statut vendable n’est accordé que lorsque les trois preuves sont réelles.</p></div><Btn onClick={load} disabled={busy}><RefreshCw size={13} className="mr-1 inline"/>{busy?"Actualisation…":"Actualiser"}</Btn></div></Card><div className="grid gap-3 md:grid-cols-3">{checks.map(c=><Card key={c.key} className="p-5"><div className="flex items-center justify-between gap-3"><div className="text-sm font-semibold">{c.label}</div>{c.pass?<CheckCircle2 size={20} className="text-emerald-300"/>:<XCircle size={20} className="text-amber-200"/>}</div><div className="mt-3 text-xs text-slate-500">{c.evidence}</div><div className="mt-4 text-[10px] font-bold uppercase tracking-[.15em] text-slate-400">{c.pass?"PREUVE VALIDÉE":"PREUVE MANQUANTE"}</div></Card>)}</div><Card><Title icon={Target} eyebrow="Blocage actuel" title="Le prochain verrou à lever"/><div className="p-5"><div className="text-xl font-semibold">{blocker}</div><p className="mt-2 text-sm text-slate-400">{data?.next_blocker==="sellable_product"?"Transformer la preuve technique en un produit Founding V10 que David peut réellement activer pour un premier client.":data?.next_blocker==="revenue_offer"?"Rendre au moins une offre génératrice de revenu réellement activable.":sellable?"Les preuves minimales de vendabilité sont réunies.":"Compléter la preuve technique avant toute promesse commerciale."}</p></div></Card><Card><Title icon={BarChart3} eyebrow="Preuves" title="Mesures actuelles"/><div className="grid gap-px bg-white/8 sm:grid-cols-4">{[["Alpha technique",m.alpha_technical_gate],["Founding V10",m.founding_v10_sellable],["Offres live",`${m.revenue_offers_live??0}/${m.revenue_offers_target??3}`],["Missions ouvertes",m.open_missions]].map(([l,v])=><div key={l} className="bg-[#0d1117] p-5"><div className="text-[10px] uppercase text-slate-600">{l}</div><div className="mt-2 text-xl font-semibold">{v??"—"}</div></div>)}</div></Card><Card className="p-5"><div className="flex gap-3"><ShieldCheck size={18} className="text-slate-500"/><div><div className="text-xs font-semibold">Truth layer · Sellability Gate V1</div><p className="mt-2 text-xs text-slate-600">Décision déterministe. Aucun LLM ne peut déclarer CAP vendable. Promesse commerciale autorisée uniquement lorsque les preuves minimales sont validées.</p></div></div></Card></div>
}

function AttentionCenter(){
  const[data,setData]=useState(null),[busy,setBusy]=useState(false),[error,setError]=useState(""),[ok,setOk]=useState("");
  async function load(){setBusy(true);setError("");const{data:p,error:e}=await supabase.rpc("cap_get_my_attention_center_v1");setBusy(false);if(e)return setError(e.message);if(p?.contract!=="attention-center-v1")return setError("Contrat Attention Center incompatible.");setData(p)}
  useEffect(()=>{load()},[]);
  async function markRead(id){setError("");setOk("");const{data:r,error:e}=await supabase.rpc("cap_mark_my_notification_read_v1",{p_notification_id:id});if(e)return setError(e.message);if(!r?.changed)return setError("Notification déjà traitée ou indisponible.");setOk("Notification marquée comme lue.");await load()}
  const counts=data?.counts||{}, items=arr(data?.attention), notifications=arr(data?.notifications);
  return <div className="space-y-5"><Notice error={error} ok={ok}/><div className="grid gap-3 sm:grid-cols-4">{[["À traiter",counts.open_signals],["Critiques",counts.critical],["Avertissements",counts.warnings],["Notifications non lues",counts.unread_notifications]].map(([l,v])=><Card key={l} className="p-4"><div className="text-[10px] uppercase tracking-[.14em] text-slate-600">{l}</div><div className="mt-2 text-2xl font-semibold">{v??"—"}</div></Card>)}</div><Card><Title icon={AlertTriangle} eyebrow="Attention Center" title="Ce qui mérite votre attention maintenant" right={<Btn onClick={load} disabled={busy}><RefreshCw size={13} className="mr-1 inline"/>{busy?"Actualisation…":"Actualiser"}</Btn>}/><div className="divide-y divide-white/8">{items.length?items.map((x,i)=><div key={x.id||i} className="flex items-start justify-between gap-4 px-5 py-4"><div><div className="text-sm font-medium">{x.title}</div>{x.body&&<div className="mt-1 text-xs text-slate-500">{x.body}</div>}<div className="mt-2 text-[10px] text-slate-700">Détecté {datetime(x.detected_at)} · source {x.source_type||"CAP"}</div></div><Severity severity={x.severity}/></div>):<Empty text="Aucun signal ouvert." sub="CAP ne fabrique aucune urgence fictive."/>}</div></Card><Card><Title icon={BellRing} eyebrow="Notifications" title="À lire"/><div className="divide-y divide-white/8">{notifications.length?notifications.map(n=><div key={n.id} className="flex items-start justify-between gap-4 px-5 py-4"><div><div className="text-sm">{n.title}</div>{n.body&&<div className="mt-1 text-xs text-slate-500">{n.body}</div>}<div className="mt-2 text-[10px] text-slate-700">{datetime(n.created_at)} · {n.channel}</div></div><Btn onClick={()=>markRead(n.id)}>Marquer comme lu</Btn></div>):<Empty text="Aucune notification non lue."/>}</div></Card><Card className="p-5"><div className="flex gap-3"><ShieldCheck size={18} className="text-slate-500"/><div><div className="text-xs font-semibold">Truth layer · Attention Center V1</div><p className="mt-2 text-xs text-slate-600">Priorisation déterministe. Aucun LLM ne crée l’urgence et aucune action n’est exécutée sans validation humaine.</p></div></div></Card></div>
}

function SignalCenter(){
  const[data,setData]=useState(null),[error,setError]=useState(""),[busy,setBusy]=useState(true);
  async function load(){setBusy(true);setError("");const{data:p,error:e}=await supabase.rpc("cap_get_my_signal_center_v1");setBusy(false);if(e)return setError(e.message);const c=p?.contract||{};if(c.name!==SIGNAL_CONTRACT.name||c.version!==SIGNAL_CONTRACT.version||c.status!==SIGNAL_CONTRACT.status)return setError("Contrat Signal Center incompatible.");setData(p)}
  useEffect(()=>{load()},[]);
  if(busy)return <Card className="p-6 text-sm text-slate-500">Analyse des signaux réels…</Card>;
  if(error)return <Notice error={error}/>;
  const counts=data?.counts||{},signals=arr(data?.signals);
  return <div className="space-y-5">
    <div className="grid gap-3 sm:grid-cols-4">{[["Critiques",counts.critical,"critical"],["Avertissements",counts.warning,"warning"],["Informations",counts.info,"info"],["Total ouvert",counts.open,"open"]].map(([l,v,k])=><Card key={k} className="p-4"><div className="text-[10px] uppercase tracking-[.16em] text-slate-600">{l}</div><div className="mt-2 text-3xl font-semibold">{v??0}</div></Card>)}</div>
    <Card><Title icon={BellRing} eyebrow="Attention opérationnelle" title="Signal Center · ce qui mérite votre regard maintenant" right={<Btn onClick={load}><RefreshCw size={13} className="mr-1 inline"/>Actualiser</Btn>}/><div className="divide-y divide-white/8">{signals.length?signals.map(s=><div key={s.id} className="grid gap-3 px-5 py-4 md:grid-cols-[1fr_auto]"><div><div className="flex flex-wrap items-center gap-2"><Severity severity={s.severity}/><span className="text-[10px] uppercase tracking-[.12em] text-slate-600">{s.source_type||s.type}</span></div><div className="mt-3 text-sm font-semibold text-slate-100">{s.title}</div>{s.body&&<div className="mt-1 text-sm text-slate-400">{s.body}</div>}<div className="mt-2 text-[10px] text-slate-600">Détecté {datetime(s.detected_at)} · règle {s.metadata?.rule||"CAP"}</div></div><div className="self-center text-right text-[10px] text-slate-600">Source réelle<br/><span className="text-slate-400">{s.source_type||"cockpit"}</span></div></div>):<Empty text="Aucun signal ouvert." sub="CAP ne crée pas d’alerte fictive."/>}</div></Card>
    <div className="rounded-xl border border-white/8 bg-black/15 px-4 py-3 text-[10px] text-slate-600">Signal Engine V1 · règles déterministes · données du cockpit autorisées uniquement.</div>
  </div>
}

function AIBrief(){
  const[brief,setBrief]=useState(null),[gen,setGen]=useState(null),[question,setQuestion]=useState("Que devrais-je faire maintenant pour avancer de manière réaliste ?"),[proposal,setProposal]=useState(null),[selected,setSelected]=useState(null),[busy,setBusy]=useState(false),[genBusy,setGenBusy]=useState(false),[actionBusy,setActionBusy]=useState(false),[error,setError]=useState(""),[decision,setDecision]=useState(null);
  async function load(){setBusy(true);setError("");const{data:p,error:e}=await supabase.rpc("cap_get_my_ai_brief_v1");setBusy(false);if(e)return setError(e.message);const c=p?.contract||{};if(c.name!==AI_CONTRACT.name||c.version!==AI_CONTRACT.version||c.status!==AI_CONTRACT.status)return setError("Contrat CAP AI Brief incompatible.");setBrief(p)}
  useEffect(()=>{load()},[]);
  async function generate(){setGenBusy(true);setError("");setGen(null);setProposal(null);setSelected(null);setDecision(null);const{data,error}=await supabase.functions.invoke("cap-ai-context-v1",{body:{question:question.trim()||undefined}});setGenBusy(false);if(error)return setError(error.message||"Appel CAP AI impossible.");if(data?.error)return setError(data.detail||data.message||data.error);const c=data?.contract||{};if(c.name!=="CAP_AI_GENERATIVE_CONTEXT"||c.version!=="1.0.0")return setError("Contrat CAP AI génératif incompatible.");setGen(data)}
  async function stage(opt){if(!gen?.interaction_id||!opt?.key)return;setActionBusy(true);setError("");setDecision(null);const{data:r,error:e}=await supabase.rpc("cap_stage_my_ai_option_v1",{p_interaction_id:gen.interaction_id,p_option_key:opt.key});setActionBusy(false);if(e)return setError(e.message);setSelected(opt);setProposal({id:r?.proposal_id,title:opt.action_title||opt.title,rationale:opt.why,payload:{title:opt.action_title||opt.title},status:r?.status||"proposed"})}
  async function decide(choice){if(!proposal?.id)return;setActionBusy(true);setError("");const{data:r,error:e}=await supabase.rpc("cap_decide_my_action_v1",{p_proposal_id:proposal.id,p_decision:choice});setActionBusy(false);if(e)return setError(e.message);setDecision(r);setProposal(x=>x?{...x,status:r?.status||x.status}:x)}
  if(busy&&!brief)return <div className="py-12 text-center text-sm text-slate-500">Chargement CAP AI…</div>;
  const b=brief?.brief||{},ev=brief?.evidence||{},fc=ev.finance||{},counts=ev.counts||{},d=gen?.decision||{},truth=gen?.truth||{},options=arr(d.options);
  return <div className="space-y-5">
    <Notice error={error}/>
    <Card className="overflow-hidden"><div className="border-b border-white/8 bg-white/[0.025] p-6"><div className="flex items-center gap-3"><div className="rounded-xl border border-violet-300/15 bg-violet-300/8 p-2"><Sparkles size={19} className="text-violet-200"/></div><div><div className="text-[10px] font-semibold uppercase tracking-[.22em] text-slate-500">CAP AI · contexte sécurisé</div><h2 className="mt-1 text-xl font-semibold">De l’observation à la décision</h2></div><Btn onClick={load} disabled={busy} className="ml-auto"><RefreshCw size={13} className="mr-1 inline"/>Actualiser contexte</Btn></div><p className="mt-5 max-w-4xl text-base leading-7 text-slate-300">{b.summary||"Aucun brief disponible."}</p></div><div className="grid gap-px bg-white/8 md:grid-cols-2"><div className="bg-[#0d1117] p-6"><div className="text-[10px] uppercase tracking-[.18em] text-slate-600">Priorité déterministe</div><div className="mt-3 text-xl font-semibold">{b.priority||"—"}</div></div><div className="bg-[#0d1117] p-6"><div className="text-[10px] uppercase tracking-[.18em] text-slate-600">Prochaine action détectée</div><div className="mt-3 text-xl font-semibold">{b.next_action||"—"}</div></div></div></Card>

    <Card><Title icon={BrainCircuit} eyebrow="CAP AI génératif" title="Demander une analyse contextualisée"/><div className="p-6"><Field label="Question au copilote"><Input value={question} onChange={e=>setQuestion(e.target.value)} placeholder="Que devrais-je faire maintenant ?"/></Field><div className="mt-4"><button onClick={generate} disabled={genBusy} className="rounded-xl border border-violet-300/20 bg-violet-300/10 px-5 py-3 text-sm font-semibold text-violet-100 disabled:opacity-50">{genBusy?"CAP AI analyse…":"Analyser avec CAP AI"}</button></div><div className="mt-3 text-[10px] text-slate-600">Le LLM reçoit uniquement le contexte CAP autorisé. Il conseille mais n’exécute jamais directement.</div></div></Card>

    {gen&&<Card className="overflow-hidden"><Title icon={Sparkles} eyebrow="Analyse générative" title={d.priority||"Décision contextualisée"}/><div className="p-6"><p className="text-base leading-7 text-slate-300">{d.summary}</p><div className="mt-5 rounded-xl border border-white/8 bg-black/15 p-4"><div className="text-[10px] uppercase tracking-[.16em] text-slate-600">Pourquoi</div><div className="mt-2 text-sm leading-6 text-slate-400">{d.reasoning}</div><div className="mt-3 text-[10px] text-slate-600">Confiance : {d.confidence||"—"} · Sources : {arr(d.sources_used).join(", ")||"—"}</div></div><div className="mt-5 grid gap-4 lg:grid-cols-3">{options.map((o,i)=><div key={o.key||i} className="rounded-2xl border border-white/10 bg-white/[0.025] p-5"><div className="text-[10px] uppercase tracking-[.16em] text-violet-200/70">Option {i+1}</div><div className="mt-2 text-base font-semibold">{o.title}</div><p className="mt-3 text-sm leading-6 text-slate-400">{o.why}</p><div className="mt-4 space-y-2 text-xs"><div><span className="text-emerald-200">Bénéfice :</span> <span className="text-slate-400">{o.benefit}</span></div><div><span className="text-amber-200">Risque :</span> <span className="text-slate-400">{o.risk}</span></div></div><button onClick={()=>stage(o)} disabled={actionBusy||proposal?.status==="proposed"} className="mt-5 w-full rounded-xl border border-white/10 bg-white/5 px-3 py-2.5 text-xs font-semibold text-slate-200 disabled:opacity-40">Choisir cette option</button></div>)}</div></div></Card>}

    {proposal&&<Card className="overflow-hidden"><Title icon={ShieldCheck} eyebrow="Validation humaine · BUILD 005 conservé" title="CAP prépare, vous décidez"/><div className="p-6"><div className="text-lg font-semibold">{proposal.title}</div><p className="mt-3 max-w-4xl text-sm leading-6 text-slate-400">{proposal.rationale}</p><div className="mt-4 rounded-xl border border-white/8 bg-black/15 p-4"><div className="text-[10px] uppercase tracking-[.16em] text-slate-600">Option sélectionnée</div><div className="mt-2 text-sm text-slate-300">{selected?.action_title||proposal.title}</div><div className="mt-1 text-[10px] text-slate-600">Statut : {proposal.status} · aucune exécution avant votre validation explicite.</div></div>{proposal.status==="proposed"?<div className="mt-5 flex flex-wrap gap-3"><button disabled={actionBusy} onClick={()=>decide("accept")} className="rounded-xl border border-emerald-400/20 bg-emerald-400/10 px-5 py-3 text-sm font-semibold text-emerald-200 disabled:opacity-50">Accepter et exécuter</button><button disabled={actionBusy} onClick={()=>decide("reject")} className="rounded-xl border border-white/10 bg-white/5 px-5 py-3 text-sm text-slate-300 disabled:opacity-50">Refuser</button></div>:<div className="mt-5 text-sm text-slate-400">Décision enregistrée : <b>{proposal.status}</b>.</div>}{decision?.executed&&<div className="mt-4 rounded-xl border border-emerald-400/15 bg-emerald-400/8 p-4 text-sm text-emerald-200">Action exécutée après validation humaine. Une mission réelle a été créée et la décision est tracée.</div>}{decision?.status==="rejected"&&<div className="mt-4 rounded-xl border border-white/10 bg-white/5 p-4 text-sm text-slate-300">Option refusée. Aucune action n’a été exécutée.</div>}</div></Card>}

    <Card><Title icon={ShieldCheck} eyebrow="Truth layer" title="Ce que CAP AI fait — et ne fait pas — dans BUILD 005"/><div className="grid gap-3 p-5 sm:grid-cols-4">{[["LLM utilisé",gen?truth.llm_used?"oui":"non":"pas encore appelé"],["Modèle",gen?truth.model:"—"],["Contexte","autorisé uniquement"],["Action sans accord","jamais"]].map(([l,v])=><div key={l} className="rounded-xl border border-white/8 bg-black/15 p-3"><div className="text-[10px] uppercase text-slate-600">{l}</div><div className="mt-2 text-sm font-semibold">{String(v??"—")}</div></div>)}</div><div className="px-5 pb-5 text-xs text-slate-500">BUILD 005 ajoute un LLM réel au-dessus des preuves déterministes. Le LLM reste consultatif : toute option doit encore passer par le moteur de validation humaine BUILD 005.</div></Card>
    <div className="grid gap-3 sm:grid-cols-4">{[["Missions ouvertes",counts.open_missions],["Signaux ouverts",counts.open_signals],["Notifications",counts.unread_notifications],["Échéances 30 j",fc.due_30d]].map(([l,v])=><Card key={l} className="p-4"><div className="text-[10px] uppercase tracking-[.14em] text-slate-600">{l}</div><div className="mt-2 text-2xl font-semibold">{v??0}</div></Card>)}</div>
  </div>
}

function Documents({uid}){const[rows,setRows]=useState([]),[error,setError]=useState(""),[ok,setOk]=useState("");const[f,setF]=useState({title:"",document_type:"",tags:""});async function load(){const{data,error}=await supabase.from("documents").select("*").order("created_at",{ascending:false});if(error)setError(error.message);else setRows(data||[])}useEffect(()=>{load()},[]);async function add(e){e.preventDefault();const{error}=await supabase.from("documents").insert({user_id:uid,title:f.title.trim(),document_type:f.document_type||null,tags:f.tags.split(",").map(x=>x.trim()).filter(Boolean),source:"manual",metadata:{build:"V10-007",storage_status:"not_uploaded"}});if(error)return setError(error.message);setF({title:"",document_type:"",tags:""});setOk("Référence document enregistrée.");load()}return <div className="space-y-5"><Notice error={error} ok={ok}/><Card><Title icon={Plus} eyebrow="Documents" title="Ajouter une référence"/><form onSubmit={add} className="grid gap-3 p-5 sm:grid-cols-3"><Field label="Titre"><Input required value={f.title} onChange={e=>setF({...f,title:e.target.value})}/></Field><Field label="Type"><Input value={f.document_type} onChange={e=>setF({...f,document_type:e.target.value})}/></Field><Field label="Tags séparés par virgule"><Input value={f.tags} onChange={e=>setF({...f,tags:e.target.value})}/></Field><div className="sm:col-span-3"><Btn type="submit" primary>Enregistrer la référence</Btn></div></form><div className="px-5 pb-4 text-[10px] text-amber-200/70">BUILD 005 gère le registre documentaire. Le téléversement de fichiers dans un stockage sécurisé n’est pas encore activé et n’est pas simulé.</div></Card><Card><Title icon={FileText} eyebrow="Registre" title="Documents"/><div className="divide-y divide-white/8">{rows.length?rows.map(d=><div key={d.id} className="px-5 py-4"><div className="text-sm">{d.title}</div><div className="mt-1 text-[10px] text-slate-600">{d.document_type||"type non défini"} · {arr(d.tags).join(", ")||"sans tag"} · {date(d.created_at)}</div></div>):<Empty text="Aucun document enregistré."/>}</div></Card></div>}

function Parameters({uid}){const[cfg,setCfg]=useState(null),[mods,setMods]=useState([]),[error,setError]=useState(""),[ok,setOk]=useState("");async function load(){const[c,m]=await Promise.all([supabase.from("user_cockpit_configs").select("*").eq("is_active",true).maybeSingle(),supabase.from("user_modules").select("module_key,position,is_enabled,settings").order("position")]);if(c.error||m.error)return setError(c.error?.message||m.error?.message);setCfg(c.data);setMods(m.data||[])}useEffect(()=>{load()},[]);async function save(){if(!cfg)return;const{error}=await supabase.from("user_cockpit_configs").update({language:cfg.language,theme:cfg.theme}).eq("id",cfg.id);if(error)return setError(error.message);setOk("Paramètres enregistrés.");load()}return <div className="space-y-5"><Notice error={error} ok={ok}/><Card><Title icon={Settings} eyebrow="Cockpit" title="Configuration active"/><div className="grid gap-4 p-5 sm:grid-cols-2">{cfg?<><Field label="Langue"><Select value={cfg.language} onChange={e=>setCfg({...cfg,language:e.target.value})}><option value="fr">Français</option><option value="nl">Nederlands</option><option value="en">English</option></Select></Field><Field label="Thème"><Select value={cfg.theme} onChange={e=>setCfg({...cfg,theme:e.target.value})}><option value="night">Night</option><option value="day">Day</option><option value="system">System</option></Select></Field><div className="sm:col-span-2 text-xs text-slate-500">Mode : {cfg.cockpit_mode} · Config : {cfg.config_version}</div><div className="sm:col-span-2"><Btn onClick={save} primary><Save size={13} className="mr-1 inline"/>Enregistrer</Btn></div></>:<Empty text="Aucune configuration active."/>}</div></Card><Card><Title icon={LayoutDashboard} eyebrow="Modules" title="Modules activés"/><div className="grid gap-2 p-5 sm:grid-cols-2 lg:grid-cols-3">{mods.map(m=><div key={m.module_key} className="rounded-xl border border-white/8 bg-black/15 p-3"><div className="text-xs font-medium">{m.module_key}</div><div className="mt-1 text-[10px] text-slate-600">position {m.position} · {m.is_enabled?"actif":"inactif"}</div></div>)}</div></Card></div>}

function FoundingProduct(){
 const[data,setData]=useState(null),[busy,setBusy]=useState(false),[error,setError]=useState(""),[price,setPrice]=useState(""),[saved,setSaved]=useState("");
 async function load(){setBusy(true);setError("");const{data:p,error:e}=await supabase.rpc("cap_get_my_founding_product_v1");setBusy(false);if(e)return setError(e.message);if(p?.contract!=="founding-product-v1")return setError("Contrat Founding Product incompatible.");setData(p);setPrice(p?.offer?.price_eur??"")}
 useEffect(()=>{load()},[]);
 async function approve(){const n=Number(String(price).replace(',', '.'));if(!n||n<=0)return setError("Indiquez un prix réel avant validation.");setBusy(true);setError("");setSaved("");const{error:e}=await supabase.rpc("cap_set_my_founding_offer_v1",{p_price_eur:n,p_approve:true});setBusy(false);if(e)return setError(e.message);setSaved("Offre Founding V10 validée humainement.");await load()}
 if(!data)return <Card className="p-6">{busy?"Chargement du produit Founding V10…":<Notice error={error}/>}</Card>;const o=data.offer||{},r=data.readiness||{};
 return <div className="space-y-5"><Notice error={error} ok={saved}/><Card className="p-6"><div className="text-[10px] font-semibold uppercase tracking-[.22em] text-slate-500">FOUNDING PRODUCT · ACTIVATION GATE</div><h1 className="mt-2 text-3xl font-semibold">{o.name||"CAP Founding V10"}</h1><p className="mt-3 max-w-3xl text-sm text-slate-400">{o.promise}</p><div className="mt-5 inline-flex rounded-full border border-white/10 px-3 py-1.5 text-xs">{data.sellable?"PRODUIT VENDABLE":"À FINALISER AVANT VENTE"}</div></Card><div className="grid gap-4 lg:grid-cols-2"><Card><Title icon={Sparkles} eyebrow="Ce que le client voit" title="Preview Founding V10"/><div className="p-5 space-y-2">{arr(o.preview_scope).map(x=><div key={x} className="flex gap-2 text-sm text-slate-300"><CheckCircle2 size={16} className="mt-0.5 text-emerald-300"/>{x}</div>)}</div></Card><Card><Title icon={PackageCheck} eyebrow="Ce que CAP active" title="Cockpit opérationnel"/><div className="p-5 space-y-2">{arr(o.activation_scope).map(x=><div key={x} className="flex gap-2 text-sm text-slate-300"><CheckCircle2 size={16} className="mt-0.5 text-emerald-300"/>{x}</div>)}</div></Card></div><Card><Title icon={Target} eyebrow="Gate commercial humain" title="Prix & validation"/><div className="p-5"><p className="text-sm text-slate-400">CAP ne choisit pas votre prix. Le produit ne passe à READY qu’après un prix réel et votre validation explicite.</p><div className="mt-4 flex flex-wrap items-end gap-3"><Field label="Prix Founding V10 · EUR"><Input type="number" min="1" step="1" value={price} onChange={e=>setPrice(e.target.value)} placeholder="Prix à décider"/></Field><Btn primary onClick={approve} disabled={busy}>{busy?"Validation…":"Valider l’offre Founding V10"}</Btn></div></div></Card><Card><Title icon={ShieldCheck} eyebrow="Readiness" title="Preuves d’activation"/><div className="grid gap-px bg-white/8 sm:grid-cols-4">{[["Périmètre défini",r.scope_defined],["Template activable",r.activation_template_ready],["Prix défini",r.price_defined],["Validation humaine",r.human_approved]].map(([l,v])=><div className="bg-[#0d1117] p-5" key={l}><div className="text-xs text-slate-500">{l}</div><div className="mt-2 font-semibold">{v?"VALIDÉ":"MANQUANT"}</div></div>)}</div></Card><Card className="p-5"><div className="flex gap-3"><ShieldCheck size={18} className="text-slate-500"/><div><div className="text-xs font-semibold">Truth layer · Founding Product V1</div><p className="mt-2 text-xs text-slate-600">Même moteur pour Preview et cockpit activé. Aucun développement spécifique promis. Prix et validation commerciale restent humains.</p></div></div></Card></div>
}

function Shell({session,data,onRefresh,refreshing,onSignOut}){const[page,setPage]=useState("command"),[open,setOpen]=useState(false);const pageName=NAV.find(x=>x[2]===page)?.[0]||"Command Center";const uid=session.user.id;const nav=<div className="flex h-full flex-col"><div className="border-b border-white/8 px-5 py-5"><div className="text-[11px] font-bold tracking-[.27em] text-slate-500">CAP</div><div className="mt-2 text-sm font-semibold">Business Pro Executive</div><div className="mt-1 text-[10px] tracking-[.18em] text-slate-600">V10 · BUILD 008</div></div><nav className="flex-1 space-y-1 p-3">{NAV.map(([l,I,k])=><button key={k} onClick={()=>{setPage(k);setOpen(false)}} className={cls("flex w-full items-center gap-3 rounded-xl px-3 py-3 text-left text-sm",page===k?"bg-white/8 text-white":"text-slate-500 hover:bg-white/5 hover:text-slate-300")}><I size={17}/><span>{l}</span>{page===k&&<ChevronRight size={14} className="ml-auto"/>}</button>)}</nav><div className="border-t border-white/8 p-3"><button onClick={onSignOut} className="flex w-full items-center gap-3 rounded-xl px-3 py-3 text-sm text-slate-500"><LogOut size={17}/>Déconnexion</button></div></div>;return <div className="min-h-screen bg-[#0d1117] text-slate-100"><aside className="fixed inset-y-0 left-0 z-20 hidden w-64 border-r border-white/8 bg-[#0b0f15] lg:block">{nav}</aside>{open&&<div className="fixed inset-0 z-40 lg:hidden"><button className="absolute inset-0 bg-black/70" onClick={()=>setOpen(false)}/><aside className="relative h-full w-72 bg-[#0b0f15]">{nav}<button onClick={()=>setOpen(false)} className="absolute right-3 top-3"><X size={18}/></button></aside></div>}<main className="lg:pl-64"><header className="sticky top-0 z-10 border-b border-white/8 bg-[#0d1117]/90 backdrop-blur-xl"><div className="mx-auto flex max-w-[1500px] items-center gap-4 px-4 py-4 sm:px-6 lg:px-8"><button onClick={()=>setOpen(true)} className="rounded-xl border border-white/10 p-2 lg:hidden"><Menu size={18}/></button><div className="flex-1"><div className="text-[10px] uppercase tracking-[.23em] text-slate-500">{pageName}</div><div className="text-sm text-slate-300">CAP Business Pro Executive V10</div></div><div className="hidden items-center gap-2 rounded-full border border-emerald-400/15 bg-emerald-400/8 px-3 py-1.5 text-[10px] text-emerald-200 sm:flex"><ShieldCheck size={13}/>COCKPIT OPÉRATIONNEL</div>{page==="command"&&<Btn onClick={onRefresh} disabled={refreshing}><RefreshCw size={13} className="mr-1 inline"/>{refreshing?"Actualisation…":"Actualiser"}</Btn>}</div></header><div className="mx-auto max-w-[1500px] px-4 py-6 sm:px-6 lg:px-8">{page==="command"&&<Command data={data} onRefresh={onRefresh} refreshing={refreshing}/>} {page==="sellability"&&<SellabilityGate/>} {page==="founding"&&<FoundingProduct/>} {page==="attention"&&<AttentionCenter/>} {page==="signals"&&<SignalCenter/>} {page==="ai"&&<AIBrief/>} {page==="agenda"&&<AgendaPage uid={uid} onChanged={onRefresh}/>} {page==="finance"&&<FinancePage uid={uid} onChanged={onRefresh}/>} {page==="cashbook"&&<Cashbook uid={uid}/>} {page==="kpi"&&<KPIPage uid={uid} onChanged={onRefresh}/>} {page==="documents"&&<Documents uid={uid}/>} {page==="settings"&&<Parameters uid={uid}/>}<footer className="mt-8 flex justify-between border-t border-white/8 py-5 text-[10px] tracking-[.12em] text-slate-700"><span>CAP BUSINESS PRO EXECUTIVE V10 · BUILD 008</span><span>{data?.contract?.name} · v{data?.contract?.version}</span></footer></div></main></div>}

function App(){const[session,setSession]=useState(null),[boot,setBoot]=useState(true),[data,setData]=useState(null),[error,setError]=useState(""),[refresh,setRefresh]=useState(false);useEffect(()=>{let a=true;supabase.auth.getSession().then(({data})=>{if(a){setSession(data.session||null);setBoot(false)}});const{data:l}=supabase.auth.onAuthStateChange((_e,s)=>{setSession(s||null);if(!s)setData(null)});return()=>{a=false;l?.subscription?.unsubscribe()}},[]);async function load(){if(!session)return;setRefresh(true);setError("");const{data:p,error:e}=await supabase.rpc("cap_get_my_command_center_v1");setRefresh(false);if(e){setData(null);return setError(`RPC indisponible : ${e.message}`)}const c=p?.contract||{};if(c.name!==CONTRACT.name||c.version!==CONTRACT.version||c.status!==CONTRACT.status){setData(null);return setError("Contrat backend incompatible avec CAP_COMMAND_CENTER v1.0.0 frozen.")}setData(p)}useEffect(()=>{if(session)load()},[session?.access_token]);if(boot)return <div className="min-h-screen bg-[#0d1117] text-slate-500 flex items-center justify-center">Initialisation sécurisée…</div>;if(!session)return <Login onReady={setSession}/>;if(error)return <div className="min-h-screen bg-[#0d1117] text-white flex items-center justify-center px-5"><Card className="max-w-lg p-6"><XCircle className="text-red-300"/><h1 className="mt-3 text-lg font-semibold">Cockpit indisponible</h1><p className="mt-2 text-sm text-slate-400">{error}</p><div className="mt-5 flex gap-2"><Btn onClick={load} primary>Réessayer</Btn><Btn onClick={()=>supabase.auth.signOut()}>Déconnexion</Btn></div></Card></div>;if(!data)return <div className="min-h-screen bg-[#0d1117] text-slate-500 flex items-center justify-center">Chargement du cockpit…</div>;return <Shell session={session} data={data} onRefresh={load} refreshing={refresh} onSignOut={()=>supabase.auth.signOut()}/>}
createRoot(document.getElementById("root")).render(<App/>);
