const { useEffect, useMemo, useRef, useState } = React;
const API = window.SHIVAI_API_BASE || (window.location.protocol.startsWith("http") ? window.location.origin : "http://localhost:3001");
let socket = null;

const navItems = [
  ["dashboard","Dashboard","DB"],
  ["campaign","Campaigns","CP"],
  ["contacts","Contacts","CT"],
  ["templates","Templates","TP"],
  ["inbox","Inbox","IN"],
  ["automation","Automation","AU"],
  ["settings","Settings","ST"],
];

function App(){
  const [user,setUser] = useState(null);
  const [checking,setChecking] = useState(true);
  const [authMode,setAuthMode] = useState("login");
  const [alert,setAlert] = useState(null);
  const [tab,setTab] = useState("dashboard");
  const [navOpen,setNavOpen] = useState(false);
  const [connected,setConnected] = useState(false);
  const [config,setConfig] = useState({ACCESS_TOKEN:"",PHONE_NUMBER_ID:"",WABA_ID:"",APP_ID:"",VERIFY_TOKEN:"",officialLinks:null,webhookPath:"/webhook"});
  const [templates,setTemplates] = useState([]);
  const [contacts,setContacts] = useLocalStorage("shivai_contacts", []);
  const [conversations,setConversations] = useState({});
  const [logs,setLogs] = useState([]);
  const [metaLive,setMetaLive] = useState(null);
  const [campaignLogs,setCampaignLogs] = useState([]);
  const [stats,setStats] = useState({total:0,accepted:0,sent:0,delivered:0,read:0,failed:0});
  const [activeCampaign,setActiveCampaign] = useState(null);
  const [search,setSearch] = useState("");

  useEffect(()=>{ checkSession(); },[]);
  useEffect(()=>{
    if(!user) return;
    socket = io(API,{withCredentials:true});
    socket.on("connect",()=>setConnected(true));
    socket.on("disconnect",()=>setConnected(false));
    socket.on("new_message",(data)=>{
      setConversations(prev=>{
        const conv = prev[data.from] || {messages:[],isHuman:false,name:data.name};
        return {...prev,[data.from]:{...conv,name:data.name,messages:[...conv.messages,{from:"user",text:data.text,time:data.time}]}};
      });
    });
    socket.on("bot_reply",(data)=>{
      setConversations(prev=>{
        const conv = prev[data.to] || {messages:[],isHuman:false};
        return {...prev,[data.to]:{...conv,messages:[...conv.messages,{from:"bot",text:data.text,time:data.time}]}};
      });
    });
    socket.on("campaign_progress",(data)=>{
      setStats(data.stats);
      setCampaignLogs(prev=>[...prev,data.log]);
      setLogs(prev=>[data.log,...prev]);
    });
    socket.on("campaign_status",(data)=>{
      if(data.stats) setStats(data.stats);
      if(data.log){
        setCampaignLogs(prev=>prev.map(log=>log.msgId && log.msgId===data.log.msgId ? data.log : log));
        setLogs(prev=>prev.map(log=>log.msgId && log.msgId===data.log.msgId ? data.log : log));
      }
    });
    socket.on("campaign_done",(data)=>{
      setStats(data.stats);
      toast("Campaign completed successfully.", "success");
    });
    loadInitialData();
    const refresh = setInterval(loadInitialData, 20000);
    return ()=>{
      clearInterval(refresh);
      socket?.disconnect();
    };
  },[user]);

  async function request(url,options={}){
    const r = await fetch(API + url, {
      credentials:"include",
      headers:{"Content-Type":"application/json",...(options.headers||{})},
      ...options,
    });
    const data = await r.json().catch(()=>({success:false,error:"Unexpected server response"}));
    if(r.status === 401){ setUser(null); setAuthMode("login"); }
    return data;
  }
  const get = (url)=>request(url);
  const post = (url,data)=>request(url,{method:"POST",body:JSON.stringify(data)});
  const del = (url)=>request(url,{method:"DELETE"});
  const toast = (msg,type="info")=>{ setAlert({msg,type}); setTimeout(()=>setAlert(null),4200); };
  async function checkSession(){
    const r = await request("/api/auth/me");
    setUser(r.user || null);
    setChecking(false);
  }
  async function loadInitialData(){
    const [cfg, conv, messageLogs, liveSummary] = await Promise.all([get("/api/config"),get("/api/conversations"),get("/api/logs"),get("/api/meta/live-summary")]);
    if(cfg) setConfig(c=>({...c,PHONE_NUMBER_ID:cfg.PHONE_NUMBER_ID||"",WABA_ID:cfg.WABA_ID||"",APP_ID:cfg.APP_ID||"",VERIFY_TOKEN:cfg.verifyToken||"",webhookPath:cfg.webhookPath||"/webhook",officialLinks:cfg.officialLinks||null,ACCESS_TOKEN:cfg.hasToken?"Saved token":c.ACCESS_TOKEN}));
    if(conv) setConversations(conv);
    if(Array.isArray(messageLogs)) setLogs(messageLogs.slice().reverse());
    if(liveSummary?.success) setMetaLive(liveSummary.data);
  }
  async function logout(){
    await post("/api/auth/logout",{});
    setUser(null);
    setAuthMode("login");
  }

  const blockedCount = contacts.filter(c=>c.blocked).length;
  const sentCount = logs.filter(l=>["accepted","sent","delivered","read"].includes(l.status)).length + (stats.accepted ?? stats.sent ?? 0);
  const failedCount = logs.filter(l=>l.status==="failed").length + stats.failed;
  const totalCount = sentCount + failedCount;
  const filteredContacts = contacts.filter(c=>(c.name+" "+c.phone).toLowerCase().includes(search.toLowerCase()));

  if(checking) return <div className="app-shell" style={{display:"grid",placeItems:"center"}}><div className="brand-mark">SA</div></div>;
  if(!user) return <AuthScreen mode={authMode} setMode={setAuthMode} setUser={setUser} request={request} alert={alert} toast={toast}/>;

  return (
    <div className="app-shell">
      <div className="layout">
        <Sidebar tab={tab} setTab={setTab} open={navOpen} setOpen={setNavOpen} connected={connected} logout={logout}/>
        <main className="content">
          <Topbar user={user} search={search} setSearch={setSearch} setNavOpen={setNavOpen} connected={connected}/>
          {alert && <div className={`alert ${alert.type}`}>{alert.msg}</div>}
          {tab==="dashboard" && <Dashboard setTab={setTab} totalCount={totalCount} sentCount={sentCount} failedCount={failedCount} blockedCount={blockedCount} contacts={contacts} templates={templates} conversations={conversations} logs={logs} connected={connected} metaLive={metaLive}/>}
          {tab==="campaign" && <Campaigns contacts={contacts} templates={templates} stats={stats} setStats={setStats} campaignLogs={campaignLogs} setCampaignLogs={setCampaignLogs} activeCampaign={activeCampaign} setActiveCampaign={setActiveCampaign} post={post} toast={toast} metaLive={metaLive}/>}
          {tab==="contacts" && <Contacts contacts={filteredContacts} setContacts={setContacts} toast={toast}/>}
          {tab==="templates" && <Templates templates={templates} setTemplates={setTemplates} get={get} post={post} del={del} toast={toast} setTab={setTab}/>}
          {tab==="inbox" && <Inbox conversations={conversations} setConversations={setConversations} post={post}/>}
          {tab==="automation" && <Automation/>}
          {tab==="settings" && <Settings config={config} setConfig={setConfig} get={get} post={post} toast={toast} user={user}/>}
        </main>
      </div>
      <div className="mobile-tabs">
        {navItems.slice(0,5).map(([id,label])=><button key={id} className={tab===id?"active":""} onClick={()=>setTab(id)}>{label}</button>)}
      </div>
    </div>
  );
}

function AuthScreen({mode,setMode,setUser,request,alert,toast}){
  const [form,setForm] = useState({name:"",email:"admin@shivai.local",password:"admin123",code:""});
  async function submit(e){
    e.preventDefault();
    if(mode==="login"){
      const r = await request("/api/auth/login",{method:"POST",body:JSON.stringify({email:form.email,password:form.password})});
      if(r.success){ setUser(r.user); toast("Welcome back. Session cookie is active.","success"); }
      else toast(r.error || "Login failed","error");
    }
    if(mode==="signup"){
      const r = await request("/api/auth/signup",{method:"POST",body:JSON.stringify(form)});
      if(r.success){ setUser(r.user); toast("Account created. You are signed in.","success"); }
      else toast(r.error || "Signup failed","error");
    }
    if(mode==="forgot"){
      const r = await request("/api/auth/forgot-password",{method:"POST",body:JSON.stringify({email:form.email})});
      if(r.success) toast(r.resetCode ? `Reset code for local testing: ${r.resetCode}` : r.message, "success");
      else toast(r.error || "Could not generate reset code","error");
    }
    if(mode==="reset"){
      const r = await request("/api/auth/reset-password",{method:"POST",body:JSON.stringify({email:form.email,code:form.code,password:form.password})});
      if(r.success){ toast("Password changed. Please login.","success"); setMode("login"); }
      else toast(r.error || "Reset failed","error");
    }
  }
  return (
    <div className="app-shell auth-wrap">
      <section className="auth-copy">
        <span className="brand-mark">SA</span>
        <div className="eyebrow" style={{marginTop:24}}>Bulk WhatsApp command center</div>
        <h1>Send, track, and support customers from one polished workspace.</h1>
        <p>A professional interface for WhatsApp campaigns, Meta templates, live inbox handover, contacts, automation, and performance analytics. Built with session cookies and a responsive layout for laptop, tablet, and mobile.</p>
        <div className="visual-stage">
          <div className="floating-card one"><strong>98%</strong><span>Delivery quality</span></div>
          <div className="phone-3d">
            <div className="phone-screen">
              <div className="phone-top"><span>Shiv AI</span><span>Live</span></div>
              <div className="bubble in">Hi, I want bulk WhatsApp promotion for my shop.</div>
              <div className="bubble out" style={{animationDelay:".15s"}}>Sure. Your approved campaign can reach the full audience with tracking.</div>
              <div className="bubble in" style={{animationDelay:".3s"}}>Can I see failed and blocked numbers?</div>
              <div className="bubble out" style={{animationDelay:".45s"}}>Yes. Dashboard has sent, failed, blocked, and active chat counts.</div>
            </div>
          </div>
          <div className="floating-card two"><strong>24/7</strong><span>Inbox automation</span></div>
        </div>
      </section>
      <section className="auth-card">
        <div className="auth-head"><span className="mini-mark">SA</span><div><h2>{mode==="login"?"Welcome back":mode==="signup"?"Create workspace":mode==="reset"?"Reset password":"Forgot password"}</h2><div className="fine">Default demo: admin@shivai.local / admin123</div></div></div>
        <div className="auth-tabs">
          <button className={mode==="login"?"active":""} onClick={()=>setMode("login")}>Login</button>
          <button className={mode==="signup"?"active":""} onClick={()=>setMode("signup")}>Signup</button>
          <button className={(mode==="forgot"||mode==="reset")?"active":""} onClick={()=>setMode("forgot")}>Forgot</button>
        </div>
        {alert && <div className={`alert ${alert.type}`}>{alert.msg}</div>}
        <form onSubmit={submit}>
          {mode==="signup" && <Input label="Full name" value={form.name} onChange={v=>setForm({...form,name:v})} placeholder="Campaign manager name"/>}
          <Input label="Email address" value={form.email} onChange={v=>setForm({...form,email:v})} placeholder="you@company.com"/>
          {(mode==="login"||mode==="signup"||mode==="reset") && <Input label={mode==="reset"?"New password":"Password"} type="password" value={form.password} onChange={v=>setForm({...form,password:v})} placeholder="Minimum 6 characters"/>}
          {mode==="reset" && <Input label="Reset code" value={form.code} onChange={v=>setForm({...form,code:v})} placeholder="6 digit code"/>}
          <button className="btn primary full" type="submit">{mode==="login"?"Login to dashboard":mode==="signup"?"Create account":mode==="forgot"?"Get reset code":"Update password"}</button>
          {mode==="forgot" && <button type="button" className="btn ghost full" style={{marginTop:10}} onClick={()=>setMode("reset")}>I have a reset code</button>}
        </form>
      </section>
    </div>
  );
}

function Sidebar({tab,setTab,open,setOpen,connected,logout}){
  return <aside className={`sidebar ${open?"open":""}`}>
    <div className="side-brand"><span className="mini-mark">SA</span><div><h2>Shiv AI WhatsApp</h2><span>Bulk message suite</span></div></div>
    <nav className="nav">
      {navItems.map(([id,label,ico])=><button key={id} className={tab===id?"active":""} onClick={()=>{setTab(id);setOpen(false)}}><span className="nav-ico">{ico}</span>{label}</button>)}
    </nav>
    <div className="sidebar-foot">
      <div className={`status-pill ${connected?"ok":"bad"}`}>{connected?"Server online":"Server offline"}</div>
      <p className="fine">Use approved Meta templates, clean contact lists, and review failures after every send.</p>
      <button className="btn ghost full" onClick={logout}>Logout</button>
    </div>
  </aside>;
}

function Topbar({user,search,setSearch,setNavOpen,connected}){
  return <div className="topbar">
    <button className="btn ghost mobile-menu" onClick={()=>setNavOpen(true)}>Menu</button>
    <div className="search"><input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Search contacts by name or phone"/></div>
    <div className="user-chip"><span className={`status-pill ${connected?"ok":"bad"}`}>{connected?"Live":"Offline"}</span><span className="avatar">{user.name?.slice(0,1).toUpperCase()}</span><div className="identity"><strong>{user.name}</strong><div className="fine">{user.role}</div></div></div>
  </div>;
}

function Dashboard({setTab,totalCount,sentCount,failedCount,blockedCount,contacts,templates,conversations,logs,connected,metaLive}){
  const activeChats = Object.keys(conversations).length;
  const liveDelivery = metaLive?.delivery || {};
  const liveTemplates = metaLive?.templates || {};
  const liveHealth = metaLive?.health || {};
  return <>
    <PageTitle title="Dashboard" sub="Professional overview for bulk WhatsApp delivery, failures, blocks, and live support." action={<button className="btn primary" onClick={()=>setTab("campaign")}>New campaign</button>}/>
    <div className="hero-strip">
      <div className="command-card">
        <div className="eyebrow" style={{color:"#b9ffe7"}}>Today command panel</div>
        <h2>Keep every campaign visible from launch to reply.</h2>
        <p>Monitor sends, failed messages, blocked contacts, template readiness, and inbox handover from a single responsive workspace.</p>
        <div className="quick-actions">
          <button className="btn" onClick={()=>setTab("contacts")}>Import contacts</button>
          <button className="btn" onClick={()=>setTab("templates")}>Manage templates</button>
          <button className="btn" onClick={()=>setTab("inbox")}>Open inbox</button>
        </div>
      </div>
      <div className="panel">
        <h3>System health</h3>
        <div className="health-list">
          <Health label="Realtime backend" ok={connected}/>
          <Health label="Contacts loaded" ok={contacts.length>0} text={`${contacts.length} contacts`}/>
          <Health label="Approved templates" ok={(liveTemplates.approved || templates.filter(t=>t.status==="APPROVED").length)>0} text={`${liveTemplates.approved ?? templates.filter(t=>t.status==="APPROVED").length} ready`}/>
          <Health label="Meta credentials" ok={liveHealth.tokenSaved && liveHealth.phoneNumberConfigured && liveHealth.wabaConfigured} text={liveHealth.tokenSaved ? "Saved" : "Pending"}/>
          <Health label="Active inbox chats" ok={activeChats>0} text={`${activeChats} chats`}/>
        </div>
      </div>
    </div>
    <div className="metric-grid">
      <Metric label="Message send count" value={totalCount} sub="All campaign attempts" tint="#e8fbf3"/>
      <Metric label="Success count" value={sentCount} sub="Sent through Meta API" tint="#dcfce7"/>
      <Metric label="Failure count" value={failedCount} sub="Rejected or API failed" tint="#fff1f2"/>
      <Metric label="Block count" value={blockedCount} sub="Opt-out and blocked contacts" tint="#fff7e8"/>
    </div>
    <div className="live-meta-grid">
      <div className="live-meta-card">
        <div>
          <span className="eyebrow">Meta live</span>
          <h3>{liveDelivery.deliveryRate || 0}% delivery rate</h3>
          <p>Accepted {liveDelivery.accepted || 0}, delivered {liveDelivery.delivered || 0}, read {liveDelivery.read || 0}, pending {liveDelivery.pending || 0}. Auto-refreshes every 20 seconds.</p>
        </div>
        <div className="live-ring" style={{"--value":`${Math.min(100,liveDelivery.deliveryRate || 0)}%`}}><strong>{liveDelivery.readRate || 0}%</strong><span>read</span></div>
      </div>
      <div className="panel live-panel">
        <h3>Top templates</h3>
        {(metaLive?.topTemplates || []).length ? metaLive.topTemplates.map(item=><div className="live-row" key={item.name}><strong>{item.name}</strong><span>{item.delivered}/{item.total} delivered</span></div>) : <p className="fine">{metaLive?.metaError || "No Meta template activity yet."}</p>}
      </div>
      <div className="panel live-panel">
        <h3>Recent Meta errors</h3>
        {(metaLive?.recentErrors || []).length ? metaLive.recentErrors.map((item,i)=><div className="live-row error" key={i}><strong>{item.templateName || "Unlinked"}</strong><span>{item.error}</span></div>) : <p className="fine">No recent delivery errors recorded.</p>}
      </div>
    </div>
    <div className="grid-2 templates-grid">
      <div className="panel"><h3>Recent activity</h3><Activity logs={logs}/></div>
      <div className="panel"><h3>Growth snapshot</h3><MiniChart sent={sentCount} failed={failedCount} contacts={contacts.length} chats={activeChats}/></div>
    </div>
  </>;
}

function Campaigns({contacts,templates,stats,setStats,campaignLogs,setCampaignLogs,activeCampaign,setActiveCampaign,post,toast,metaLive}){
  const [camp,setCamp] = useState({name:"May Offer Campaign",templateName:"",language:"en_US",audienceMode:"all",batchId:""});
  const [campaignMedia,setCampaignMedia] = useState({file:null,preview:"",payload:null});
  const [variableMap,setVariableMap] = useState({});
  useEffect(()=>{
    const saved = localStorage.getItem("shivai_campaign_template");
    if(saved){
      try{
        const template = JSON.parse(saved);
        setCamp(prev=>({...prev,templateName:template.name || "",language:template.language || prev.language}));
      }catch{}
      localStorage.removeItem("shivai_campaign_template");
    }
  },[]);
  const selectedTemplate = templates.find(t=>t.name===camp.templateName);
  const requiredMedia = templateMediaHeader(selectedTemplate);
  const variableCount = templateVariableCount(selectedTemplate);
  const batches = useMemo(()=>{
    const map = new Map();
    contacts.filter(c=>c.batchId).forEach(c=>{
      const existing = map.get(c.batchId) || {id:c.batchId,name:c.sourceName || "CSV import",count:0,columns:new Set()};
      existing.count++;
      Object.keys(c.fields || {}).forEach(key=>existing.columns.add(key));
      map.set(c.batchId,existing);
    });
    return [...map.values()].map(item=>({...item,columns:[...item.columns]}));
  },[contacts]);
  const audienceContacts = useMemo(()=>{
    if(camp.audienceMode==="csv") return contacts.filter(c=>c.batchId && (!camp.batchId || c.batchId===camp.batchId));
    if(camp.audienceMode==="manual") return contacts.filter(c=>!c.batchId);
    return contacts;
  },[contacts,camp.audienceMode,camp.batchId]);
  const audienceColumns = useMemo(()=>allContactColumns(audienceContacts),[audienceContacts]);
  useEffect(()=>{
    setVariableMap(prev=>{
      const next = {};
      for(let i=1;i<=variableCount;i++) next[i] = prev[i] || audienceColumns[i-1] || "name";
      return next;
    });
  },[variableCount,audienceColumns.join("|")]);
  function chooseCampaignMedia(file){
    if(campaignMedia.preview) URL.revokeObjectURL(campaignMedia.preview);
    if(!file) return setCampaignMedia({file:null,preview:"",payload:null});
    setCampaignMedia({file,preview:URL.createObjectURL(file),payload:null});
  }
  useEffect(()=>{
    if(campaignMedia.preview) URL.revokeObjectURL(campaignMedia.preview);
    setCampaignMedia({file:null,preview:"",payload:null});
  },[camp.templateName]);
  const acceptedCount = stats.accepted ?? stats.sent ?? 0;
  const deliveredCount = stats.delivered ?? 0;
  const amountSpent = stats.amountSpent ?? 0;
  const progress = stats.total ? Math.round(((acceptedCount+stats.failed)/stats.total)*100) : 0;
  async function runCampaign(){
    if(!camp.templateName) return toast("Select an approved template first.","error");
    const sendable = audienceContacts.filter(c=>!c.blocked).map(contact=>({
      ...contact,
      vars:Array.from({length:variableCount},(_,index)=>contactFieldValue(contact,variableMap[index+1]))
    }));
    if(!sendable.length) return toast("No sendable contacts available.","error");
    if(variableCount && Object.values(variableMap).some(value=>!value)) return toast("Map every template variable before sending.","error");
    let mediaUpload = null;
    if(requiredMedia){
      if(!campaignMedia.file) return toast(`Attach a ${requiredMedia.mediaType} file for this template before starting the campaign.`,"error");
      mediaUpload = await fileToUploadPayload(campaignMedia.file, requiredMedia.mediaType);
    }
    setCampaignLogs([]);
    setStats({total:sendable.length,accepted:0,sent:0,delivered:0,read:0,failed:0});
    const r = await post("/api/campaign/send",{contacts:sendable,templateName:camp.templateName,language:camp.language,campaignName:camp.name,category:selectedTemplate?.category,mediaUpload});
    if(r.success){ setActiveCampaign(r.campaignId); toast("Campaign started. Meta acceptance and delivery will update live.","success"); }
    else if(r.invalidContacts?.length){
      toast(`${r.error} ${r.invalidContacts.map(c=>`${c.name || "Contact"}: ${c.phone}`).join("; ")}`,"error");
    }
    else toast(r.error || "Campaign failed to start","error");
  }
  function exportLogs(){
    const csv = "Time,Name,Phone,Status,Details\n" + campaignLogs.map(l=>`${l.time},${l.name},${l.phone},${l.status},${l.msgId||l.error||""}`).join("\n");
    const a = document.createElement("a");
    a.href = URL.createObjectURL(new Blob([csv],{type:"text/csv"}));
    a.download = "campaign_results.csv";
    a.click();
  }
  return <>
    <PageTitle title="Campaigns" sub="Launch approved template campaigns with live delivery tracking."/>
    <div className="grid-2">
      <div className="tool-card">
        <h3>Campaign setup</h3>
        <div className="row">
          <Input label="Campaign name" value={camp.name} onChange={v=>setCamp({...camp,name:v})}/>
          <div className="field"><label>Language</label><select value={camp.language} onChange={e=>setCamp({...camp,language:e.target.value})}><option value="en_US">English (US)</option><option value="en_GB">English (UK)</option><option value="ta">Tamil</option><option value="hi">Hindi</option><option value="te">Telugu</option></select></div>
        </div>
        <div className="field"><label>Approved template</label><select value={camp.templateName} onChange={e=>setCamp({...camp,templateName:e.target.value})}><option value="">Select template</option>{templates.filter(t=>t.status==="APPROVED").map(t=><option key={t.name} value={t.name}>{t.name}</option>)}</select></div>
        {selectedTemplate && <div className="campaign-template-card">
          <div>
            <strong>{selectedTemplate.name}</strong>
            <p className="fine">{selectedTemplate.language} - {selectedTemplate.category} - {requiredMedia ? `${titleCase(requiredMedia.mediaType)} header template` : "Text template, no media attachment required"}</p>
          </div>
          <div className={`badge ${requiredMedia ? "warn" : "ok"}`}>{requiredMedia ? "Media required" : "Ready"}</div>
          <p>{templateTextBody(selectedTemplate)}</p>
        </div>}
        <div className="campaign-section">
          <div className="section-head">
            <div><h3>Audience</h3><p className="fine">Choose old contacts, new CSV contacts, or everyone.</p></div>
            <span className="badge ok">{audienceContacts.filter(c=>!c.blocked).length} sendable</span>
          </div>
          <div className="segmented-control">
            {[["all","All contacts"],["csv","CSV imports"],["manual","Old/manual"]].map(([id,label])=><button key={id} className={camp.audienceMode===id?"active":""} onClick={()=>setCamp({...camp,audienceMode:id})}>{label}</button>)}
          </div>
          {camp.audienceMode==="csv" && <div className="field"><label>CSV file/import batch</label><select value={camp.batchId} onChange={e=>setCamp({...camp,batchId:e.target.value})}><option value="">All CSV imports</option>{batches.map(batch=><option key={batch.id} value={batch.id}>{batch.name} ({batch.count})</option>)}</select></div>}
          <div className="audience-preview">
            {audienceContacts.slice(0,5).map(contact=><div className="audience-chip" key={contact.id}><strong>{contact.name || "Unnamed"}</strong><span>{contact.phone}</span></div>)}
            {!audienceContacts.length && <p className="fine">No contacts match this audience.</p>}
          </div>
        </div>
        {variableCount > 0 && <div className="campaign-section variable-mapper">
          <div className="section-head">
            <div><h3>Template variable mapping</h3><p className="fine">Map each Meta variable to a contact or CSV column. These values fill {`{{1}}`}, {`{{2}}`}, and so on.</p></div>
            <span className="badge warn">{variableCount} variable{variableCount>1?"s":""}</span>
          </div>
          <div className="mapping-grid">
            {Array.from({length:variableCount},(_,index)=>{
              const number = index+1;
              return <div className="mapping-card" key={number}>
                <div><strong>{`{{${number}}}`}</strong><small>{contactFieldValue(audienceContacts[0],variableMap[number]) || "Preview value"}</small></div>
                <select value={variableMap[number] || ""} onChange={e=>setVariableMap(prev=>({...prev,[number]:e.target.value}))}>
                  <option value="">Choose column</option>
                  {audienceColumns.map(column=><option key={column} value={column}>{column}</option>)}
                </select>
              </div>;
            })}
          </div>
        </div>}
        {requiredMedia && <div className="campaign-media-card">
          <div>
            <strong>{titleCase(requiredMedia.mediaType)} attachment required</strong>
            <p className="fine">This Meta template has a {requiredMedia.mediaType} header. Choose the local file before running the campaign; the backend uploads it to WhatsApp and sends it with every template message.</p>
          </div>
          <label className="media-picker-btn">
            Choose {requiredMedia.mediaType}
            <input type="file" accept={mediaAccept(requiredMedia.mediaType)} onChange={e=>chooseCampaignMedia(e.target.files[0])}/>
          </label>
          {campaignMedia.file && <div className="campaign-media-preview">
            {requiredMedia.mediaType==="image" && <img src={campaignMedia.preview}/>}
            {requiredMedia.mediaType==="video" && <video src={campaignMedia.preview} muted controls/>}
            {requiredMedia.mediaType==="document" && <span>Document: {campaignMedia.file.name}</span>}
          </div>}
        </div>}
        <p className="fine">Blocked contacts are skipped automatically. CSV columns are preserved and can be mapped to template variables.</p>
        <div className="actions"><button className="btn primary" onClick={runCampaign}>Start campaign</button></div>
      </div>
      <div className="tool-card">
        <h3>Live progress</h3>
        <div className="grid-3">
          <Metric label="Total" value={stats.total} sub="Queue" tint="#eef2ff"/>
          <Metric label="Accepted" value={acceptedCount} sub="Meta accepted" tint="#dcfce7"/>
          <Metric label="Delivered" value={deliveredCount} sub="User received" tint="#e0f2fe"/>
          <Metric label="Failed" value={stats.failed} sub="Needs review" tint="#fff1f2"/>
          <Metric label="Usage" value={money(amountSpent)} sub="Estimated spend" tint="#fef9c3"/>
          <Metric label="Read" value={stats.read || 0} sub="Opened by user" tint="#f3e8ff"/>
        </div>
      <div className="progress"><span style={{width:`${progress}%`}}></span></div>
        <p className="fine">{activeCampaign ? `Campaign ${activeCampaign}: ${acceptedCount} accepted by Meta, ${deliveredCount} delivered, ${stats.read || 0} read, ${money(amountSpent)} estimated usage. If delivered stays 0, Meta webhook status is not reaching this server or Meta returned a delivery error.` : "No active campaign yet."}</p>
        <DeliveryTroubleshooter metaLive={metaLive} stats={stats}/>
      </div>
    </div>
    <div className="panel" style={{marginTop:16}}>
      <h3>Delivery log</h3>
      <div className="log-box">{campaignLogs.length ? campaignLogs.map((l,i)=><div key={i} className={l.status==="failed"?"fail":""}>[{new Date(l.time).toLocaleTimeString()}] {displayStatus(l.status)} {l.name || "Contact"} {l.phone} {l.msgId || l.error || l.note || ""}</div>) : <span className="muted">Campaign events will appear here.</span>}</div>
      <div className="actions"><button className="btn ghost" onClick={exportLogs}>Export CSV</button></div>
    </div>
  </>;
}

function contactFieldValue(contact,column){
  if(!contact || !column) return "";
  if(column==="name") return contact.name || "";
  if(column==="phone") return contact.phone || "";
  if(column.startsWith("var")) return contact.vars?.[Number(column.replace("var",""))-1] || "";
  return contact.fields?.[column] ?? contact[column] ?? "";
}

function allContactColumns(contacts){
  const set = new Set(["name","phone"]);
  contacts.forEach(contact=>{
    Object.keys(contact.fields || {}).forEach(key=>set.add(key));
    (contact.vars || []).forEach((_,index)=>set.add(`var${index+1}`));
  });
  return [...set];
}

function DeliveryTroubleshooter({metaLive,stats}){
  const webhook = metaLive?.webhook || {};
  const hasPending = (stats.accepted || stats.sent || 0) > 0 && !(stats.delivered || 0) && !(stats.failed || 0);
  if(!hasPending && webhook.lastStatusAt) return null;
  return <div className="delivery-help">
    <strong>{webhook.lastStatusAt ? "Waiting for delivery callback" : "Webhook callback not seen yet"}</strong>
    <p>{webhook.lastStatusAt ? `Last status callback: ${new Date(webhook.lastStatusAt).toLocaleString()}. If this campaign is still pending, check recipient privacy, phone number, and template eligibility.` : "Meta accepted the request, but this app has not received a delivery/read/failed callback. For localhost, your ngrok URL must be active and configured in Meta Webhooks."}</p>
    <div className="help-points">
      <span>Callback URL: your-ngrok-url/webhook</span>
      <span>Verify token: {webhook.verifyToken || "shivai_verify_token"}</span>
      <span>Subscribe the Webhook field named messages</span>
    </div>
  </div>;
}

function Contacts({contacts,setContacts,toast}){
  const [contact,setContact] = useState({name:"",phone:"",vars:""});
  const [importMode,setImportMode] = useState("append");
  const columns = useMemo(()=>allContactColumns(contacts),[contacts]);
  const csvBatches = useMemo(()=>{
    const map = new Map();
    contacts.filter(c=>c.batchId).forEach(c=>{
      const item = map.get(c.batchId) || {id:c.batchId,name:c.sourceName,count:0};
      item.count++;
      map.set(c.batchId,item);
    });
    return [...map.values()];
  },[contacts]);
  function addContact(){
    if(!contact.phone) return toast("Phone number is required.","error");
    const fields = {name:contact.name,phone:contact.phone};
    const vars = contact.vars?contact.vars.split(",").map(v=>v.trim()):[];
    vars.forEach((value,index)=>fields[`var${index+1}`]=value);
    setContacts(prev=>[...prev,{...contact,id:Date.now(),blocked:false,vars,fields,source:"manual"}]);
    setContact({name:"",phone:"",vars:""});
    toast("Contact added.","success");
  }
  function importCSV(e){
    const file = e.target.files[0];
    if(!file) return;
    const reader = new FileReader();
    reader.onload = ev=>{
      const parsed = parseCSV(ev.target.result);
      const batchId = `csv_${Date.now()}`;
      const nameKey = detectColumn(parsed.headers,["name","full name","customer","contact"]);
      const phoneKey = detectColumn(parsed.headers,["phone","number","mobile","whatsapp","contact number"]);
      if(!phoneKey) return toast("CSV needs a phone/number/mobile column.","error");
      const imported = parsed.rows.map(row=>{
        const fields = {...row};
        const name = row[nameKey] || row.name || "";
        const phone = row[phoneKey] || "";
        return {id:Date.now()+Math.random(),name,phone,vars:[],fields,blocked:false,source:"csv",batchId,sourceName:file.name,csvColumns:parsed.headers};
      }).filter(c=>c.phone);
      setContacts(prev=>importMode==="replace" ? imported : [...prev,...imported]);
      toast(`Imported ${imported.length} contacts with ${parsed.headers.length} columns from ${file.name}.`,"success");
      e.target.value = "";
    };
    reader.readAsText(file);
  }
  return <>
    <PageTitle title="Contacts" sub="Build clean contact lists, mark blocked users, and map template variables."/>
    <div className="contact-hero">
      <div>
        <span className="eyebrow">Audience data</span>
        <h2>{contacts.length} contacts, {columns.length} usable columns</h2>
        <p>Import CSV files with any columns, keep old contacts, and map columns directly into campaign variables.</p>
      </div>
      <div className="contact-stats"><strong>{csvBatches.length}</strong><span>CSV imports</span></div>
    </div>
    <div className="grid-2 contact-workspace">
      <div className="tool-card">
        <h3>Add contact</h3>
        <div className="row-3">
          <Input label="Name" value={contact.name} onChange={v=>setContact({...contact,name:v})} placeholder="Arjun Kumar"/>
          <Input label="Phone with country code" value={contact.phone} onChange={v=>setContact({...contact,phone:v})} placeholder="+919876543210"/>
          <Input label="Default variables" value={contact.vars} onChange={v=>setContact({...contact,vars:v})} placeholder="Arjun, 20"/>
        </div>
        <div className="actions"><button className="btn primary" onClick={addContact}>Add contact</button></div>
      </div>
      <div className="tool-card csv-import-card">
        <h3>CSV import</h3>
        <p className="fine">Every CSV column is stored and shown for campaign mapping. Use a phone/mobile/number column for WhatsApp numbers.</p>
        <div className="segmented-control">
          <button className={importMode==="append"?"active":""} onClick={()=>setImportMode("append")}>Add to old contacts</button>
          <button className={importMode==="replace"?"active":""} onClick={()=>setImportMode("replace")}>New list only</button>
        </div>
        <label className="upload-drop">Import CSV<input type="file" accept=".csv" onChange={importCSV}/></label>
      </div>
    </div>
    <div className="panel contact-table-panel" style={{marginTop:16}}>
      <div className="section-head">
        <div><h3>Audience list ({contacts.length})</h3><p className="fine">Columns: {columns.join(", ")}</p></div>
        <span className="badge ok">{contacts.filter(c=>!c.blocked).length} active</span>
      </div>
      <div className="contact-table-wrap">
        <table className="contact-table">
          <thead><tr>{columns.map(column=><th key={column}>{column}</th>)}<th>Source</th><th>Status</th><th>Actions</th></tr></thead>
          <tbody>
            {contacts.length ? contacts.map(c=><tr key={c.id}>{columns.map(column=><td key={column}>{contactFieldValue(c,column) || "-"}</td>)}<td>{c.sourceName || c.source || "old"}</td><td><span className={`badge ${c.blocked?"bad":"ok"}`}>{c.blocked?"Blocked":"Active"}</span></td><td><div className="table-actions"><button className="btn ghost" onClick={()=>setContacts(prev=>prev.map(x=>x.id===c.id?{...x,blocked:!x.blocked}:x))}>{c.blocked?"Unblock":"Block"}</button><button className="btn danger" onClick={()=>setContacts(prev=>prev.filter(x=>x.id!==c.id))}>Remove</button></div></td></tr>) : <tr><td colSpan={columns.length+3}>No contacts yet.</td></tr>}
          </tbody>
        </table>
      </div>
    </div>
  </>;
}

function parseCSV(text){
  const rows = [];
  let row = [], value = "", quoted = false;
  for(let i=0;i<text.length;i++){
    const char = text[i], next = text[i+1];
    if(char === '"' && quoted && next === '"'){ value += '"'; i++; continue; }
    if(char === '"'){ quoted = !quoted; continue; }
    if(char === "," && !quoted){ row.push(value.trim()); value = ""; continue; }
    if((char === "\n" || char === "\r") && !quoted){
      if(char === "\r" && next === "\n") i++;
      row.push(value.trim());
      if(row.some(cell=>cell)) rows.push(row);
      row = []; value = "";
      continue;
    }
    value += char;
  }
  row.push(value.trim());
  if(row.some(cell=>cell)) rows.push(row);
  const headers = (rows.shift() || []).map((header,index)=>header || `column_${index+1}`);
  return {headers,rows:rows.map(values=>headers.reduce((obj,header,index)=>({...obj,[header]:values[index] || ""}),{}))};
}

function detectColumn(headers,candidates){
  const lower = headers.map(header=>String(header).trim().toLowerCase());
  const index = lower.findIndex(header=>candidates.some(candidate=>header===candidate || header.includes(candidate)));
  return index >= 0 ? headers[index] : "";
}

function Templates({templates,setTemplates,get,post,del,toast,setTab}){
  const [tpl,setTpl] = useState({name:"",language:"en_US",category:"MARKETING",variableType:"Number",mediaSample:"None",mediaFile:null,mediaPreview:"",headerText:"",bodyText:"Hello",footerText:"",bodyExample:"",buttons:[]});
  const [selected,setSelected] = useState(null);
  const [insights,setInsights] = useState(null);
  const [detailOpen,setDetailOpen] = useState(false);
  const [buttonMenu,setButtonMenu] = useState(false);
  const [submitReceipt,setSubmitReceipt] = useState(null);
  useEffect(()=>{ loadTemplates(); },[]);
  async function loadTemplates(){
    const r = await get("/api/templates");
    if(r.success){ setTemplates(r.data || []); toast("Templates refreshed.","success"); }
    else toast(r.error || "Could not load templates.","error");
  }
  async function selectTemplate(template){
    setSelected(template);
    setInsights(buildLocalTemplateInsights(template));
    setDetailOpen(true);
    const r = await get(`/api/templates/${encodeURIComponent(template.name)}/insights`);
    if(r.success) setInsights(r.data);
    else toast(r.error || "Template insights could not load from backend.","error");
  }
  async function createTemplate(){
    if(!tpl.name || !tpl.bodyText) return toast("Template name and body are required.","error");
    if(!/^[a-z0-9_]+$/.test(tpl.name)) return toast("Template name can use only lowercase letters, numbers, and underscores.","error");
    const variables = [...new Set((tpl.bodyText.match(/\{\{\s*\d+\s*\}\}/g) || []).map(v=>Number(v.replace(/[^\d]/g,""))))].sort((a,b)=>a-b);
    const examples = tpl.bodyExample ? tpl.bodyExample.split(",").map(v=>v.trim()).filter(Boolean) : [];
    if(variables.length){
      const expected = variables.map((_,i)=>i+1).join(",");
      if(variables.join(",") !== expected) return toast("Variables must be sequential: {{1}}, {{2}}, {{3}}.","error");
      if(examples.length !== variables.length) return toast(`Your message has ${variables.length} variable(s). Add exactly ${variables.length} sample value(s), comma separated.`,"error");
    }
    let mediaUpload = null;
    if(["Image","Video","Document"].includes(tpl.mediaSample)){
      if(!tpl.mediaFile) return toast(`Choose a local ${tpl.mediaSample.toLowerCase()} sample before submitting this media template.`,"error");
      mediaUpload = await fileToUploadPayload(tpl.mediaFile,tpl.mediaSample.toLowerCase());
    }
    const {mediaFile,mediaPreview,...payload} = tpl;
    const r = await post("/api/templates/create",{...payload,mediaUpload,bodyExample:tpl.bodyExample?tpl.bodyExample.split(",").map(v=>v.trim()):[]});
    if(r.success){
      setSubmitReceipt({name:tpl.name,status:r.data?.status || "Submitted",id:r.data?.id,waba:r.wabaId});
      toast(`Submitted to Meta: ${tpl.name}. Refresh Meta Manager and clear filters if it is not visible yet.`,"success");
      loadTemplates();
    }
    else toast(r.error || "Template submit failed.","error");
  }
  async function deleteTemplate(name){
    const r = await del(`/api/templates/${name}`);
    if(r.success){ toast("Template deleted.","success"); loadTemplates(); }
    else toast(r.error || "Could not delete template.","error");
  }
  function addButton(kind){
    const defaults = {
      URL:{kind:"URL",text:"Visit website",url:"https://www.example.com",urlType:"Static"},
      PHONE_NUMBER:{kind:"PHONE_NUMBER",text:"Call phone number",country:"IN +91",phoneNumber:""},
      VOICE_CALL:{kind:"VOICE_CALL",text:"Call on WhatsApp",activeFor:"7 days"},
      COPY_CODE:{kind:"COPY_CODE",text:"Copy offer code",offerCode:""},
      QUICK_REPLY:{kind:"QUICK_REPLY",text:"Custom"}
    };
    setTpl({...tpl,buttons:[...tpl.buttons,defaults[kind]]});
    setButtonMenu(false);
  }
  function updateButton(index,patch){
    setTpl({...tpl,buttons:tpl.buttons.map((button,i)=>i===index?{...button,...patch}:button)});
  }
  function removeButton(index){
    setTpl({...tpl,buttons:tpl.buttons.filter((_,i)=>i!==index)});
  }
  function updateMediaSample(value){
    if(tpl.mediaPreview) URL.revokeObjectURL(tpl.mediaPreview);
    setTpl({...tpl,mediaSample:value,mediaFile:null,mediaPreview:""});
  }
  function chooseMedia(file){
    if(!file) return;
    if(tpl.mediaPreview) URL.revokeObjectURL(tpl.mediaPreview);
    setTpl({...tpl,mediaFile:file,mediaPreview:URL.createObjectURL(file)});
  }
  return <>
    <PageTitle title="Templates" sub="Create, refresh, and manage Meta-approved WhatsApp message templates." action={<button className="btn ghost" onClick={loadTemplates}>Refresh</button>}/>
    <div className="grid-2 templates-grid">
      <div className="tool-card meta-create">
        <div className="meta-create-head"><div className="meta-create-title"><div className="meta-megaphone">⌁</div><div><h3>{tpl.name || "your_template_name"} · {tpl.language==="en_US"?"English":tpl.language}</h3><p>{titleCase(tpl.category)} · Default</p></div></div><button className="btn primary" onClick={createTemplate}>Submit template</button></div>
        <div className="meta-create-body">
          <section className="meta-section">
            <h3>Template name and language</h3>
            <div className="meta-field-line">
              <div className="field"><label>Name your template</label><div className="meta-input-wrap"><input value={tpl.name} onChange={e=>setTpl({...tpl,name:e.target.value.toLowerCase().replace(/\s/g,"_")})} placeholder="Enter a template name"/><span className="char-count">{tpl.name.length}/512</span></div></div>
              <div className="field"><label>Select language</label><select value={tpl.language} onChange={e=>setTpl({...tpl,language:e.target.value})}><option value="en_US">English</option><option value="en_GB">English (UK)</option><option value="ta">Tamil</option><option value="hi">Hindi</option><option value="te">Telugu</option></select></div>
            </div>
          </section>
          <section className="meta-section">
            <h3>Content</h3>
            <p className="meta-section-copy">Add a header, body and footer for your template. Cloud API hosted by Meta will review template variables and content to protect service integrity.</p>
            <div className="meta-duo">
              <div className="field"><label>Type of variable</label><select value={tpl.variableType} onChange={e=>setTpl({...tpl,variableType:e.target.value})}><option>Number</option><option>Name</option></select></div>
              <div className="field"><label>Media sample · Optional</label><select value={tpl.mediaSample} onChange={e=>updateMediaSample(e.target.value)}><option>None</option><option>Image</option><option>Video</option><option>Document</option><option>Location</option></select></div>
            </div>
            {tpl.mediaSample !== "None" && tpl.mediaSample !== "Location" && <div className="media-upload"><strong>{tpl.mediaSample} sample</strong><span>Drag and drop to upload or </span><label>choose file<input type="file" accept={tpl.mediaSample==="Image"?"image/*":tpl.mediaSample==="Video"?"video/*":".pdf,.doc,.docx,.xls,.xlsx,.txt"} onChange={e=>chooseMedia(e.target.files[0])}/></label>{tpl.mediaFile && <div className="media-file">{tpl.mediaSample}: {tpl.mediaFile.name}</div>}</div>}
            {tpl.mediaSample === "Location" && <div className="media-upload"><strong>Location sample</strong><span>Location headers are represented in preview. Meta may require location fields during template setup.</span></div>}
            <div className="field"><label>Category</label><select value={tpl.category} onChange={e=>setTpl({...tpl,category:e.target.value})}><option value="MARKETING">Marketing</option><option value="UTILITY">Utility</option><option value="AUTHENTICATION">Authentication</option></select></div>
            <div className="field"><label>Header · Optional</label><div className="meta-input-wrap"><input value={tpl.headerText} maxLength="60" onChange={e=>setTpl({...tpl,headerText:e.target.value})} placeholder="Add a short line of text to the header of your message in English"/><span className="char-count">{tpl.headerText.length}/60</span></div><div className="format-bar"><button onClick={()=>setTpl({...tpl,headerText:`${tpl.headerText} {{1}}`})}>+ Add variable</button></div></div>
            <div className="field"><label>Body</label><div className="meta-input-wrap"><textarea value={tpl.bodyText} maxLength="1024" onChange={e=>setTpl({...tpl,bodyText:e.target.value})} placeholder="Hello"/><span className="char-count body-count">{tpl.bodyText.length}/1024</span></div><div className="format-bar"><button>☻</button><button>B</button><button><i>I</i></button><button>S</button><button>{"</>"}</button><button className="add-variable" onClick={()=>setTpl({...tpl,bodyText:`${tpl.bodyText} {{${nextVariable(tpl.bodyText)}}}`})}>+ Add variable</button></div></div>
            <div className="field"><label>Footer · Optional</label><div className="meta-input-wrap"><input value={tpl.footerText} maxLength="60" onChange={e=>setTpl({...tpl,footerText:e.target.value})} placeholder="Add a short line of text to the bottom of your message in English"/><span className="char-count">{tpl.footerText.length}/60</span></div></div>
            <Input label="Sample values" value={tpl.bodyExample} onChange={v=>setTpl({...tpl,bodyExample:v})} placeholder="Arjun, 20"/>
          </section>
          <section className="meta-section">
            <h3>Buttons <span className="muted">· Optional</span></h3>
            <p className="meta-section-copy">Create buttons that let customers respond to your message or take action. Call on WhatsApp uses your connected WhatsApp Business number.</p>
            <div className="button-menu-wrap"><button className="btn ghost" onClick={()=>setButtonMenu(!buttonMenu)}>+ Add button</button>{buttonMenu && <div className="button-menu"><button onClick={()=>addButton("QUICK_REPLY")}>↩ Custom</button><button onClick={()=>addButton("URL")}>↗ Visit website</button><button onClick={()=>addButton("VOICE_CALL")}>◉ Call on WhatsApp</button><button onClick={()=>addButton("PHONE_NUMBER")}>☎ Call Phone Number</button><button onClick={()=>addButton("COPY_CODE")}>▣ Copy offer code</button></div>}</div>
            {tpl.buttons.map((button,index)=><TemplateButtonEditor key={index} button={button} index={index} updateButton={updateButton} removeButton={removeButton}/>)}
          </section>
          <TemplateCreationPreview tpl={tpl}/>
          {submitReceipt && <div className="tracking-note"><strong>Meta submission receipt:</strong> {submitReceipt.name} · {submitReceipt.status}{submitReceipt.id ? ` · ID ${submitReceipt.id}` : ""}{submitReceipt.waba ? ` · WABA ${submitReceipt.waba}` : ""}. If Meta web page does not show it, refresh that page, remove filters, and confirm the same business/WABA is selected.</div>}
          <div className="actions"><button className="btn primary" onClick={createTemplate}>Submit template</button></div>
          <div className="template-submit-dock"><span>Ready to submit? This button stays visible while you inspect large image previews.</span><button className="btn primary" onClick={createTemplate}>Submit template</button></div>
        </div>
      </div>
      <div className="panel template-library">
        <div className="template-library-head">
          <h3>Template library</h3>
          <span className="template-count">{templates.length} templates</span>
        </div>
        <div className="template-list">
          {templates.length ? templates.map(t=>
            <div className={`template-row ${selected?.name===t.name?"active":""}`} key={t.name} onClick={()=>selectTemplate(t)}>
              <div className="template-info">
                <strong>{t.name}</strong>
                <small>{t.language} - {t.category}</small>
              </div>
              <div className="template-actions">
                <span className={`badge ${t.status==="APPROVED"?"ok":t.status==="REJECTED"?"bad":"warn"}`}>{t.status}</span>
                <button className="btn danger" onClick={(e)=>{e.stopPropagation();deleteTemplate(t.name)}}>Delete</button>
              </div>
            </div>
          ) : <p className="fine">No templates loaded. Click Refresh after saving Meta API credentials.</p>}
        </div>
      </div>
    </div>
    {detailOpen && <TemplateMetaModal insights={insights} selected={selected} post={post} toast={toast} setInsights={setInsights} onUseCampaign={()=>{localStorage.setItem("shivai_campaign_template",JSON.stringify(selected));setDetailOpen(false);setTab("campaign");}} onClose={()=>setDetailOpen(false)}/>}
  </>;
}

function titleCase(value=""){
  return String(value).toLowerCase().replace(/\b\w/g,c=>c.toUpperCase());
}

function nextVariable(text=""){
  const vars = (text.match(/\{\{\s*\d+\s*\}\}/g) || []).map(v=>Number(v.replace(/[^\d]/g,"")));
  return Math.max(0,...vars)+1;
}

function templateMediaHeader(template){
  const header = template?.components?.find(c=>String(c.type).toUpperCase()==="HEADER");
  const format = String(header?.format || "").toUpperCase();
  return ["IMAGE","VIDEO","DOCUMENT"].includes(format) ? {...header,mediaType:format.toLowerCase()} : null;
}

function templateTextBody(template){
  return template?.components?.find(c=>String(c.type).toUpperCase()==="BODY")?.text || "Template body will be sent from Meta.";
}

function templateVariableCount(template){
  const body = templateTextBody(template);
  return [...new Set((body.match(/\{\{\s*\d+\s*\}\}/g) || []).map(v=>Number(v.replace(/[^\d]/g,""))))].length;
}

function mediaAccept(mediaType){
  if(mediaType==="image") return "image/*";
  if(mediaType==="video") return "video/*";
  if(mediaType==="document") return ".pdf,.doc,.docx,.xls,.xlsx,.txt,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document";
  return "*/*";
}

function displayStatus(status){
  if(status==="accepted") return "ACCEPTED BY META";
  if(status==="sent") return "SENT BY META";
  if(status==="delivered") return "DELIVERED";
  if(status==="read") return "READ";
  if(status==="failed") return "FAILED";
  if(status==="unmatched_webhook_status") return "WEBHOOK STATUS";
  return String(status || "PENDING").toUpperCase();
}

function fileToUploadPayload(file,mediaType){
  return new Promise((resolve,reject)=>{
    const reader = new FileReader();
    reader.onerror = ()=>reject(new Error("Could not read selected file."));
    reader.onload = ()=>resolve({dataUrl:reader.result,fileName:file.name,mimeType:file.type || "application/octet-stream",mediaType});
    reader.readAsDataURL(file);
  });
}

function TemplateButtonEditor({button,index,updateButton,removeButton}){
  const commonType = <div className="field"><label>Type of action</label><select value={button.kind} onChange={e=>updateButton(index,{kind:e.target.value})}><option value="QUICK_REPLY">Custom</option><option value="URL">Visit website</option><option value="VOICE_CALL">Call on WhatsApp</option><option value="PHONE_NUMBER">Call Phone Number</option><option value="COPY_CODE">Copy offer code</option></select></div>;
  if(button.kind==="PHONE_NUMBER") return <div className="template-button-editor"><div className="button-editor-grid call">{commonType}<div className="field"><label>Button text</label><input maxLength="25" value={button.text} onChange={e=>updateButton(index,{text:e.target.value})}/></div><div className="field"><label>Country</label><select value={button.country || "IN +91"} onChange={e=>updateButton(index,{country:e.target.value})}><option>IN +91</option><option>US +1</option><option>GB +44</option></select></div><div className="field"><label>Phone number</label><input maxLength="20" value={button.phoneNumber || ""} onChange={e=>updateButton(index,{phoneNumber:e.target.value})} placeholder="9876543210"/></div><button className="remove-btn" onClick={()=>removeButton(index)}>×</button></div></div>;
  if(button.kind==="VOICE_CALL") return <div className="template-button-editor"><div className="button-editor-grid voice">{commonType}<div className="field"><label>Button text</label><input maxLength="20" value={button.text} onChange={e=>updateButton(index,{text:e.target.value})}/></div><div className="field"><label>Active for</label><select value={button.activeFor || "7 days"} onChange={e=>updateButton(index,{activeFor:e.target.value})}><option>1 day</option><option>7 days</option><option>30 days</option></select></div><button className="remove-btn" onClick={()=>removeButton(index)}>×</button></div><p className="fine">WhatsApp call button calls your connected WhatsApp Business number. Calling must be enabled in WhatsApp Manager.</p></div>;
  if(button.kind==="URL") return <div className="template-button-editor"><div className="button-editor-grid">{commonType}<div className="field"><label>Button text</label><input maxLength="25" value={button.text} onChange={e=>updateButton(index,{text:e.target.value})}/></div><div className="field"><label>Website URL</label><input value={button.url || ""} onChange={e=>updateButton(index,{url:e.target.value})} placeholder="https://www.example.com"/></div><button className="remove-btn" onClick={()=>removeButton(index)}>×</button></div></div>;
  if(button.kind==="COPY_CODE") return <div className="template-button-editor"><div className="button-editor-grid copy">{commonType}<div className="field"><label>Button text</label><input disabled value="Copy offer code"/></div><div className="field"><label>Offer code</label><input maxLength="15" value={button.offerCode || ""} onChange={e=>updateButton(index,{offerCode:e.target.value})} placeholder="SAVE20"/></div><button className="remove-btn" onClick={()=>removeButton(index)}>×</button></div></div>;
  return <div className="template-button-editor"><div className="button-editor-grid copy">{commonType}<div className="field"><label>Button text</label><input maxLength="25" value={button.text} onChange={e=>updateButton(index,{text:e.target.value})}/></div><div></div><button className="remove-btn" onClick={()=>removeButton(index)}>×</button></div></div>;
}

function TemplateCreationPreview({tpl}){
  const previewButtons = tpl.buttons.slice(0,3);
  return <section className="template-preview-card">
    <h3>Template preview</h3>
    <div className="wa-canvas">
      <div className="wa-bubble">
        {tpl.mediaSample !== "None" && <PreviewMedia tpl={tpl}/>}
        {tpl.headerText && <strong>{tpl.headerText}</strong>}
        <p>{tpl.bodyText || "Hello"}</p>
        {tpl.footerText && <small className="muted">{tpl.footerText}</small>}
        <span>{new Date().toLocaleTimeString([], {hour:"2-digit",minute:"2-digit"})}</span>
        {previewButtons.length > 0 && <div className="preview-buttons">{previewButtons.map((button,i)=><span key={i}>{button.kind==="URL"?"↗":button.kind==="PHONE_NUMBER"?"☎":button.kind==="VOICE_CALL"?"◉":button.kind==="COPY_CODE"?"▣":"↩"} {button.kind==="COPY_CODE"?"Copy offer code":button.text}</span>)}</div>}
      </div>
    </div>
  </section>;
}

function PreviewMedia({tpl}){
  if(tpl.mediaSample==="Image") return <div className="preview-media">{tpl.mediaPreview ? <img src={tpl.mediaPreview}/> : <span className="placeholder">▧</span>}</div>;
  if(tpl.mediaSample==="Video") return <div className="preview-media">{tpl.mediaPreview ? <video src={tpl.mediaPreview} muted controls/> : <span className="placeholder">▶</span>}</div>;
  if(tpl.mediaSample==="Document") return <div className="preview-media"><span className="doc">📄 {tpl.mediaFile?.name || "Document sample"}</span></div>;
  if(tpl.mediaSample==="Location") return <div className="preview-media"><span className="doc">⌖ Location sample</span></div>;
  return null;
}

function buildLocalTemplateInsights(template){
  const body = template.components?.find(c=>String(c.type).toUpperCase()==="BODY")?.text || "Template body preview will appear here after Meta returns components.";
  const header = template.components?.find(c=>String(c.type).toUpperCase()==="HEADER")?.text || template.name || "Your template";
  const category = String(template.category || "MARKETING").toUpperCase();
  const rate = category==="MARKETING" ? 0.86 : category==="SERVICE" ? 0 : 0.125;
  const labels = ["7 May","8 May","9 May","10 May","11 May","12 May","13 May"];
  return {
    template:{...template,header,body,category},
    pricing:{symbol:"₹",currency:"INR",market:"India",category,deliveredMessageRate:rate,source:"Meta pricing uses delivered template messages by market and category."},
    metrics:{attempts:0,sent:0,delivered:0,read:0,replies:0,failed:0,amountSpent:0,costPerDelivered:rate},
    series:labels.map(label=>({label,sent:0,delivered:0,read:0,replies:0,errors:0})),
    topError:"--",
  };
}

function money(value,symbol="₹"){
  return `${symbol}${Number(value || 0).toFixed(2)}`;
}

function TemplateMetaModal({insights,selected,post,toast,setInsights,onUseCampaign,onClose}){
  const [test,setTest] = useState({to:"",variables:""});
  const [testMedia,setTestMedia] = useState({file:null,preview:""});
  const [sending,setSending] = useState(false);
  const requiredMedia = templateMediaHeader(selected);
  function chooseTestMedia(file){
    if(testMedia.preview) URL.revokeObjectURL(testMedia.preview);
    if(!file) return setTestMedia({file:null,preview:""});
    setTestMedia({file,preview:URL.createObjectURL(file)});
  }
  async function sendTest(){
    if(!selected || !test.to) return toast("Enter a phone number with country code.","error");
    let mediaUpload = null;
    if(requiredMedia){
      if(!testMedia.file) return toast(`Attach a ${requiredMedia.mediaType} file before sending this test.`,"error");
      mediaUpload = await fileToUploadPayload(testMedia.file,requiredMedia.mediaType);
    }
    setSending(true);
    const variables = test.variables.split(",").map(v=>v.trim()).filter(Boolean);
    const r = await post(`/api/templates/${encodeURIComponent(selected.name)}/send-test`,{to:test.to,variables,mediaUpload});
    setSending(false);
    if(r.success){ setInsights(r.insights); toast("Test template sent. Performance card updated.","success"); }
    else toast(r.error || "Could not send test template.","error");
  }
  return <div className="template-modal-backdrop" onClick={onClose}>
    <div className="template-modal" onClick={e=>e.stopPropagation()}>
      <div className="template-modal-head">
        <div>
          <h3>{selected?.name || "Template details"}</h3>
          <p>{selected?.language || "en_US"} - {selected?.category || "MARKETING"} performance and Meta pricing view</p>
        </div>
        <div style={{display:"flex",gap:10,alignItems:"center"}}>
          <button className="btn ghost" onClick={onUseCampaign}>Use in campaign</button>
          <button className="icon-btn" onClick={onClose} aria-label="Close template details">×</button>
        </div>
      </div>
      <TemplateMetaDetail insights={insights} selected={selected} test={test} setTest={setTest} sendTest={sendTest} sending={sending} requiredMedia={requiredMedia} testMedia={testMedia} chooseTestMedia={chooseTestMedia}/>
    </div>
  </div>;
}

function TemplateMetaDetail({insights,selected,test,setTest,sendTest,sending,requiredMedia,testMedia,chooseTestMedia}){
  if(!selected) return <div className="template-detail"><p className="fine">Click any template to open its Meta-style performance page, pricing, WhatsApp preview, and error analytics.</p></div>;
  const data = insights || buildLocalTemplateInsights(selected);
  const m = data.metrics || {};
  const p = data.pricing || {};
  return <div className="template-detail">
    <div className="template-command">
      <div>
        <h4>Send this template</h4>
        <p>Send a live test through your connected Meta backend. Successful sends update the performance and amount-spent cards.</p>
      </div>
      <div className="send-test-form">
        <input value={test?.to || ""} onChange={e=>setTest({...test,to:e.target.value})} placeholder="+919876543210"/>
        <input value={test?.variables || ""} onChange={e=>setTest({...test,variables:e.target.value})} placeholder="Sample values, comma separated"/>
        {requiredMedia && <label className="media-picker-btn small">Attach {requiredMedia.mediaType}<input type="file" accept={mediaAccept(requiredMedia.mediaType)} onChange={e=>chooseTestMedia(e.target.files[0])}/></label>}
        <button className="btn primary" disabled={sending} onClick={sendTest}>{sending ? "Sending..." : "Send test"}</button>
      </div>
    </div>
    {requiredMedia && testMedia?.file && <div className="campaign-media-preview test-media-preview">
      {requiredMedia.mediaType==="image" && <img src={testMedia.preview}/>}
      {requiredMedia.mediaType==="video" && <video src={testMedia.preview} muted controls/>}
      {requiredMedia.mediaType==="document" && <span>Document: {testMedia.file.name}</span>}
    </div>}
    <div className="template-detail-grid">
      <aside className="meta-side">
        <div className="meta-card wa-preview">
          <h4>Your template</h4>
          <div className="wa-canvas">
            <div className="wa-bubble">
              <strong>{data.template?.header || data.template?.name}</strong>
              <p>{data.template?.body}</p>
              <span>{new Date().toLocaleTimeString([], {hour:"2-digit",minute:"2-digit"})}</span>
            </div>
          </div>
        </div>
        <div className="insight-card meta-card">
          <span className="external-mark">↗</span>
          <h4>See the complete picture</h4>
          <p>Monitor performance, cost, delivery, read rate, replies, and Meta delivery errors for this template.</p>
        </div>
        <div className="insight-card meta-card">
          <h4>Top block reason</h4>
          <p className="fine">Last 7 days</p>
          <h3>{data.topError || "--"}</h3>
        </div>
      </aside>
      <section>
        <div className="price-grid">
          <div className="price-card"><strong>Amount spent</strong><div className="price">{money(m.amountSpent,p.symbol)}</div></div>
          <div className="price-card"><strong>Cost per message delivered</strong><div className="price">{money(m.costPerDelivered,p.symbol)}</div></div>
        </div>
        <div className="meta-card">
          <h4>Performance</h4>
          <div className="segment-tabs"><span className="active">Trend</span><span>Funnel</span></div>
          <div className="perf-grid">
            <div className="perf-tile"><strong>Attempts</strong><span>{m.attempts || 0}</span></div>
            <div className="perf-tile"><strong>Accepted by Meta</strong><span>{m.accepted || m.sent || 0}</span></div>
            <div className="perf-tile"><strong>Messages sent</strong><span>{m.sent || 0}</span></div>
            <div className="perf-tile"><strong>Messages delivered</strong><span>{m.delivered || 0}{m.deliveryRate ? ` (${m.deliveryRate}%)` : ""}</span></div>
            <div className="perf-tile"><strong>Messages read</strong><span>{m.read || 0}{m.readRate ? ` (${m.readRate}%)` : ""}</span></div>
            <div className="perf-tile"><strong>Pending callbacks</strong><span>{m.pending || 0}</span></div>
            <div className="perf-tile"><strong>Failed</strong><span>{m.failed || 0}{m.failureRate ? ` (${m.failureRate}%)` : ""}</span></div>
          </div>
          <TrendChart series={data.series || []}/>
        </div>
        <div className="meta-card callback-card">
          <h4>Latest callback data</h4>
          {(data.recentLogs || []).length ? data.recentLogs.map((item,i)=><div className="callback-row" key={i}><div><strong>{displayStatus(item.metaStatus || item.status)}</strong><small>{item.phone || item.msgId || "Meta callback"}</small></div><span>{item.time ? new Date(item.time).toLocaleTimeString() : "--"}</span></div>) : <p className="fine">No webhook callbacks linked to this template yet.</p>}
        </div>
        <div className="error-card">
          <h4>Error messages</h4>
          <p className="fine">Select an error for details.</p>
          <div className="segment-tabs"><span className="active">Top errors</span><span>All errors</span></div>
          <TrendChart series={(data.series || []).map(x=>({...x,sent:x.errors || 0,delivered:0,read:0,replies:0}))} errorOnly/>
          <div className="error-line"><i></i><span>{data.topError || "No template delivery errors"} &nbsp; {m.failed || 0}</span></div>
        </div>
        <p className="meta-note">Pricing follows Meta's per-delivered-template-message model. Current app defaults are India INR and can be updated in the backend rate table.</p>
        {data.tracking && <div className={`tracking-note ${m.failed ? "error" : ""}`}><strong>Backend tracking:</strong> {data.tracking.matchedLogs} matching logs for this template, {data.tracking.totalLogs} total delivery logs. {m.failed ? `Meta rejected ${m.failed} send attempt(s). Check Error messages below. ` : ""}{data.tracking.unlinkedLogs ? `${data.tracking.unlinkedLogs} older logs are not linked to any template. ` : ""}{data.tracking.note}</div>}
      </section>
    </div>
  </div>;
}

function TrendChart({series,errorOnly=false}){
  const rows = series.length ? series : [{label:"Today",sent:0,delivered:0,read:0,replies:0,errors:0}];
  const max = Math.max(1,...rows.flatMap(x=>[x.sent||0,x.delivered||0,x.read||0,x.replies||0,x.errors||0]));
  const w = 760, h = 250, left = 38, top = 22, bottom = 34;
  const x = i => left + (rows.length===1 ? 0 : i*((w-left-20)/(rows.length-1)));
  const y = v => top + (max-v)*((h-top-bottom)/max);
  const path = key => rows.map((row,i)=>`${i ? "L" : "M"}${x(i)},${y(row[key]||0)}`).join(" ");
  const lines = errorOnly ? [["sent","#ef5b68","Ecosystem health"]] : [["sent","#e35b65","Messages sent"],["delivered","#5b0b68","Messages delivered"],["read","#077b83","Messages read"],["replies","#064638","Unique replies"]];
  return <div className="chart-wrap">
    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      {[0,1].map(v=><g key={v}><line x1={left} x2={w-10} y1={y(v*max)} y2={y(v*max)} stroke="#d8dedc"/><text x={left-10} y={y(v*max)+5} textAnchor="end" fontSize="12">{v*max}</text></g>)}
      {lines.map(([key,color])=><path key={key} d={path(key)} fill="none" stroke={color} strokeWidth="3" strokeLinejoin="round"/>)}
      {rows.map((row,i)=><text key={row.label} x={x(i)} y={h-8} textAnchor="middle" fontSize="12">{row.label}</text>)}
    </svg>
    {!errorOnly && <div className="chart-legend">{lines.map(([key,color,label])=><span key={key}><i style={{background:color}}></i>{label}</span>)}</div>}
  </div>;
}

function Inbox({conversations,setConversations,post}){
  const [active,setActive] = useState(null);
  const [reply,setReply] = useState("");
  const chatEnd = useRef(null);
  useEffect(()=>chatEnd.current?.scrollIntoView({behavior:"smooth"}),[active,conversations]);
  async function sendReply(){
    if(!reply || !active) return;
    await post("/api/send-message",{to:active,text:reply});
    setConversations(prev=>{
      const conv = prev[active] || {messages:[],isHuman:true};
      return {...prev,[active]:{...conv,messages:[...conv.messages,{from:"agent",text:reply,time:new Date().toISOString()}]}};
    });
    setReply("");
  }
  async function toggle(phone){
    const next = !conversations[phone]?.isHuman;
    await post("/api/handover",{phone,isHuman:next});
    setConversations(prev=>({...prev,[phone]:{...prev[phone],isHuman:next}}));
  }
  const entries = Object.entries(conversations);
  return <>
    <PageTitle title="Inbox" sub="Switch between bot automation and human handover for customer replies."/>
    <div className="inbox-grid">
      <div className="panel"><h3>Conversations</h3><div className="list">{entries.length ? entries.map(([phone,conv])=><div key={phone} className={`conversation ${active===phone?"active":""}`} onClick={()=>setActive(phone)}><strong>{conv.name || phone}</strong><small>{conv.messages?.slice(-1)[0]?.text?.slice(0,58) || "No preview"}</small><div style={{marginTop:8}}><span className={`badge ${conv.isHuman?"warn":"ok"}`}>{conv.isHuman?"Human":"Bot"}</span></div></div>) : <p className="fine">Incoming webhook messages will appear here.</p>}</div></div>
      <div className="panel">{!active ? <div style={{minHeight:360,display:"grid",placeItems:"center"}}><p className="fine">Select a conversation to view messages.</p></div> : <><div style={{display:"flex",alignItems:"center",justifyContent:"space-between",gap:12,marginBottom:12}}><div><h3 style={{margin:0}}>{conversations[active]?.name || active}</h3><p className="fine" style={{margin:0}}>{active}</p></div><button className="btn ghost" onClick={()=>toggle(active)}>{conversations[active]?.isHuman?"Switch to bot":"Take over"}</button></div><div className="chat-window">{(conversations[active]?.messages || []).map((m,i)=><div key={i} className={`msg ${m.from}`}><strong style={{fontSize:11,textTransform:"uppercase"}}>{m.from}</strong><div>{m.text}</div><small className="muted">{new Date(m.time).toLocaleTimeString()}</small></div>)}<div ref={chatEnd}/></div>{conversations[active]?.isHuman ? <div className="chat-bar"><input value={reply} onChange={e=>setReply(e.target.value)} onKeyDown={e=>e.key==="Enter"&&sendReply()} placeholder="Type your reply"/><button className="btn primary" onClick={sendReply}>Send</button></div> : <p className="fine" style={{textAlign:"center"}}>Bot mode is active. Use Take over to reply manually.</p>}</>}</div>
    </div>
  </>;
}

function Automation(){
  return <>
    <PageTitle title="Automation" sub="Useful tabs for bulk messaging operations and compliance workflows."/>
    <div className="grid-3">
      {[
        ["Smart follow-ups","Plan follow-up campaigns for customers who clicked, replied, or did not respond."],
        ["Opt-out control","Keep STOP, unsubscribe, and blocked numbers away from future campaigns."],
        ["Quality monitor","Review failure reasons and template quality before scaling sends."],
      ].map(([h,p])=><div className="tool-card" key={h}><h3>{h}</h3><p className="fine">{p}</p><button className="btn ghost">Coming next</button></div>)}
    </div>
  </>;
}

function Settings({config,setConfig,get,post,toast,user}){
  async function save(){
    const clean = {...config};
    if(clean.ACCESS_TOKEN === "Saved token") delete clean.ACCESS_TOKEN;
    delete clean.officialLinks;
    delete clean.webhookPath;
    const r = await post("/api/config",clean);
    toast(r.success ? "Credentials saved." : r.error || "Save failed", r.success ? "success" : "error");
  }
  async function test(){
    toast("Testing Meta connection...","info");
    const r = await get("/api/test-connection");
    toast(r.success ? `Connected to ${r.data.display_phone_number || r.data.id}` : r.error, r.success ? "success" : "error");
  }
  return <>
    <PageTitle title="Settings" sub="Secure workspace credentials and account details."/>
    <div className="grid-2">
      <div className="tool-card"><h3>Meta API credentials</h3><Input label="Access token" type="password" value={config.ACCESS_TOKEN} onChange={v=>setConfig({...config,ACCESS_TOKEN:v})}/><Input label="Phone Number ID" value={config.PHONE_NUMBER_ID} onChange={v=>setConfig({...config,PHONE_NUMBER_ID:v})}/><Input label="WhatsApp Business Account ID" value={config.WABA_ID} onChange={v=>setConfig({...config,WABA_ID:v})}/><Input label="Meta App ID for media template samples" value={config.APP_ID} onChange={v=>setConfig({...config,APP_ID:v})} placeholder="Required for image/video/document template creation"/><Input label="Webhook verify token" value={config.VERIFY_TOKEN || ""} onChange={v=>setConfig({...config,VERIFY_TOKEN:v})}/><div className="actions"><button className="btn ghost" onClick={test}>Test connection</button><button className="btn primary" onClick={save}>Save credentials</button></div></div>
      <div className="panel"><h3>Account session</h3><table className="table"><tbody><tr><td>Name</td><td>{user.name}</td></tr><tr><td>Email</td><td>{user.email}</td></tr><tr><td>Role</td><td>{user.role}</td></tr><tr><td>Cookie</td><td>HTTP-only session, 8 hour expiry</td></tr></tbody></table><p className="fine">Accounts are stored in memory for this local microservice. Use a database before production deployment.</p></div>
      <div className="tool-card"><h3>Official Meta pages</h3><p className="fine">Use these direct pages to verify the same App ID, WABA ID, Phone Number ID, template library, and webhook subscription that this backend uses.</p><div className="list">{Object.entries(config.officialLinks || {}).filter(([key])=>key!=="graphVersion").map(([key,url])=><div className="list-row" key={key}><div><strong>{titleCase(key.replace(/([A-Z])/g," $1"))}</strong><small>{url}</small></div><a className="btn ghost" href={url} target="_blank" rel="noreferrer">Open</a></div>)}</div><p className="fine" style={{marginTop:12}}>Webhook callback path: {config.webhookPath || "/webhook"} · Verify token: {config.VERIFY_TOKEN || "not set"} · Graph API: {config.officialLinks?.graphVersion || "v25.0"}</p></div>
    </div>
  </>;
}

function PageTitle({title,sub,action}){return <div className="page-title"><div><h1>{title}</h1><p>{sub}</p></div>{action}</div>;}
function Metric({label,value,sub,tint}){return <div className="metric-card" style={{"--tint":tint}}><div className="metric-top"><span>{label}</span></div><div className="metric-value">{value}</div><div className="metric-sub">{sub}</div></div>;}
function Health({label,ok,text}){return <div className="health-item"><span>{label}</span><span className={`status-pill ${ok?"ok":"warn"}`}>{text || (ok?"Ready":"Pending")}</span></div>;}
function Activity({logs}){return <div className="list">{logs.length ? logs.slice(0,8).map((l,i)=><div className="list-row" key={i}><div><strong>{l.name || "Campaign contact"}</strong><small>{new Date(l.time).toLocaleString()} - {l.phone}</small></div><span className={`badge ${l.status==="failed"?"bad":"ok"}`}>{displayStatus(l.status)}</span></div>) : <p className="fine">No delivery activity yet.</p>}</div>;}
function MiniChart({sent,failed,contacts,chats}){
  const items = [["Sent",sent,"#12b886"],["Failed",failed,"#dc3d45"],["Contacts",contacts,"#2457d6"],["Chats",chats,"#6554d9"]];
  const max = Math.max(...items.map(x=>x[1]),1);
  return <div style={{display:"grid",gap:14}}>{items.map(([label,value,color])=><div key={label}><div style={{display:"flex",justifyContent:"space-between",fontWeight:800,fontSize:13}}><span>{label}</span><span>{value}</span></div><div className="progress"><span style={{width:`${Math.max(6,(value/max)*100)}%`,background:color}}></span></div></div>)}</div>;
}
function Input({label,value,onChange,type="text",placeholder=""}){return <div className="field"><label>{label}</label><input type={type} value={value} onChange={e=>onChange(e.target.value)} placeholder={placeholder}/></div>;}
function useLocalStorage(key,initial){
  const [value,setValue] = useState(()=>{try{return JSON.parse(localStorage.getItem(key)) ?? initial}catch{return initial}});
  useEffect(()=>localStorage.setItem(key,JSON.stringify(value)),[key,value]);
  return [value,setValue];
}

ReactDOM.createRoot(document.getElementById("root")).render(<App/>);
