/* AI-COS CalLab Pro — role dashboards and dependency-free SVG charts */
function DDonut({data,label='JOBS'}){const sum=data.reduce((a,x)=>a+x.n,0)||1,R=46,C=2*Math.PI*R;let off=0;return <div className="row" style={{gap:18}}><svg viewBox="0 0 120 120" style={{width:130}}><circle cx="60" cy="60" r={R} fill="none" stroke="var(--bg)" strokeWidth="15"/>{data.map((d,i)=>{let n=d.n/sum*C,e=<circle key={i} cx="60" cy="60" r={R} fill="none" stroke={d.c} strokeWidth="15" strokeDasharray={`${n} ${C-n}`} strokeDashoffset={-off} transform="rotate(-90 60 60)"/>;off+=n;return e;})}<text x="60" y="58" textAnchor="middle" style={{fontSize:20,fontWeight:800,fill:'var(--ink)'}}>{sum}</text><text x="60" y="73" textAnchor="middle" style={{fontSize:8,fill:'var(--text-3)'}}>{label}</text></svg><div style={{flex:1}}>{data.map((d,i)=><div className="row" key={i} style={{fontSize:12,marginBottom:6}}><i style={{width:8,height:8,borderRadius:3,background:d.c}}/><span style={{flex:1}}>{d.k}</span><b>{d.n}</b></div>)}</div></div>}
function DVBars({data,color='var(--primary-600)',suffix=''}){const max=Math.max(...data.map(x=>x.n),1);return <div className="row" style={{height:150,alignItems:'flex-end',gap:7}}>{data.map((d,i)=><div key={i} style={{flex:1,textAlign:'center'}}><div className="mono faint" style={{fontSize:9}}>{d.n}{suffix}</div><div title={`${d.k}: ${d.n}${suffix}`} style={{height:Math.max(3,d.n/max*105),background:i===data.length-1?color:'#8aacf1',borderRadius:'4px 4px 0 0',margin:'3px auto',width:'72%'}}/><span className="faint" style={{fontSize:9}}>{d.k}</span></div>)}</div>}
function DHBars({data}){const max=Math.max(...data.map(x=>x.n),1);return <div>{data.map((d,i)=><div className="row" key={i} style={{fontSize:12,marginBottom:9}}><span style={{width:120,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{d.k}</span><div className="progress" style={{flex:1,height:15}}><i style={{width:d.n/max*100+'%',background:d.c||'var(--primary-600)'}}/></div><b className="mono" style={{width:24,textAlign:'right'}}>{d.n}</b></div>)}</div>}
function DSpark({data,color='var(--primary-600)'}){let max=Math.max(...data),min=Math.min(...data),pts=data.map((n,i)=>`${i/(data.length-1)*100},${35-(n-min)/(max-min||1)*30}`).join(' ');return <svg viewBox="0 0 100 40" preserveAspectRatio="none" style={{height:90,width:'100%'}}><line x1="0" y1="35" x2="100" y2="35" stroke="var(--border)"/><polyline points={pts} fill="none" stroke={color} strokeWidth="2" vectorEffect="non-scaling-stroke"/></svg>}
function DashHead({title,sub}){return <div className="row" style={{justifyContent:'space-between',marginBottom:18}}><div><div className="h-page">{title}</div><div className="h-sub">{sub}</div></div><Badge kind="info" icon="refresh">Live demo data</Badge></div>}
function InsightCard({score,children}){return <div className="card card-pad" style={{background:'linear-gradient(120deg,var(--ai-bg),#fff)',borderColor:'var(--ai-line)'}}><div className="row"><span className="ai-badge-ico"><Icon name="sparkles" fill size={15}/></span><div><div className="ai-label">AI Insights · Advisory demo</div><b>Audit-readiness score: {score}/100</b></div></div><div className="muted" style={{fontSize:12.5,marginTop:9}}>{children}</div><div className="faint" style={{fontSize:10.5,marginTop:8}}>Human review required. AI suggestions never change controlled records automatically.</div></div>}
function CardChart({icon,title,children,right}){return <div className="card"><div className="card-head"><Icon name={icon} size={16} style={{color:'var(--primary-600)'}}/><div className="h-sec">{title}</div><span className="spacer"/>{right}</div><div className="card-body">{children}</div></div>}
function ManagementDashboard(){const D=DB, today=d=>new Date(d).toDateString()===D.TODAY.toDateString(), pending=D.jobs.filter(j=>!['Certified','Invoiced','Delivered'].includes(j.stage)).length,rev=D.invoices.filter(x=>new Date(x.date).getMonth()===D.TODAY.getMonth()).reduce((a,x)=>a+x.amount,0),sat=(D.feedback.reduce((a,x)=>a+x.score,0)/D.feedback.length).toFixed(1),stage=D.stages.map((k,i)=>({k,n:D.jobs.filter(j=>j.stage===k).length,c:['#94a3b8','#0891b2','#2f6fed','#c9820a','#7a5bff','#15a06b','#0f7a4f','#475569'][i]})),mix=D.disciplines.map(x=>({k:x.name,n:D.assets.filter(a=>a.discipline===x.name).length,c:x.color}));return <div className="page page-wide rise"><DashHead title="Management command centre" sub="Commercial, operational and quality performance across six calibration disciplines"/><div className="kpi-grid" style={{gridTemplateColumns:'repeat(6,1fr)',marginBottom:16}}><Kpi label="Received today" value={D.jobs.filter(j=>today(j.recvd)).length} icon="box"/><Kpi label="Jobs pending" value={pending} icon="workflow" tone="warn"/><Kpi label="Completed today" value={D.certificates.filter(c=>today(c.calDate)).length} icon="check-circle" tone="ok"/><Kpi label="Revenue MTD" value={rev.toLocaleString()} unit="SAR" icon="receipt" tone="ok"/><Kpi label="Calibration due" value={D.assets.filter(a=>(new Date(a.due)-D.TODAY)/864e5<=30).length} icon="calendar" tone="warn"/><Kpi label="Standards due" value={D.standards.filter(a=>(new Date(a.due)-D.TODAY)/864e5<=30).length} icon="gauge" tone="bad"/><Kpi label="Satisfaction" value={sat} unit="/5" icon="star" tone="ok"/><Kpi label="Technician productivity" value={Math.round(D.certificates.length/3)} unit="/ tech" icon="users"/><Kpi label="Open NCR" value={D.ncrs.filter(x=>x.stage!=='Closed').length} icon="flag" tone="warn"/><Kpi label="Open CAPA" value={D.capas.filter(x=>x.stage!=='Closed').length} icon="refresh" tone="warn"/><Kpi label="Complaints" value={D.complaints.filter(x=>x.status!=='Closed').length} icon="chat"/><Kpi label="Audit findings" value={D.findings.filter(x=>x.status==='Open').length} icon="check-shield" tone="warn"/></div><div className="dash-row-3" style={{display:'grid',gridTemplateColumns:'1.4fr 1fr 1fr',gap:16,marginBottom:16}}><CardChart icon="trend" title="Revenue trend" right={<span className="faint">SAR ’000</span>}><DVBars data={D.kpis.revenueHistory.map((n,i)=>({k:['Aug','Sep','Oct','Nov','Dec','Jan','Feb','Mar','Apr','May','Jun','Jul'][i],n}))}/></CardChart><CardChart icon="workflow" title="Jobs by stage"><DHBars data={stage}/></CardChart><CardChart icon="chart" title="Discipline mix"><DDonut data={mix} label="ASSETS"/></CardChart></div><div className="dash-row-2" style={{display:'grid',gridTemplateColumns:'1.5fr 1fr',gap:16}}><CardChart icon="users" title="Technician productivity"><DHBars data={D.staff.filter(s=>s.role==='Calibration Technician').map(s=>({k:s.name,n:D.certificates.filter(c=>c.tech===s.id).length,c:s.color}))}/></CardChart><InsightCard score={auditReadiness()}>Out-of-tolerance events are concentrated in dimensional instruments. Consider reserving Thursday afternoon for the three urgent jobs and advance the next pressure-standard drift check by seven days.</InsightCard></div></div>}
function QualityDashboard(){const D=DB,score=auditReadiness();return <div className="page page-wide rise"><DashHead title="Quality dashboard" sub="ISO/IEC 17025:2017 and ISO 9001:2015 assurance overview"/><div className="kpi-grid" style={{gridTemplateColumns:'repeat(6,1fr)',marginBottom:16}}><Kpi label="Open NCR" value={D.ncrs.filter(x=>x.stage!=='Closed').length} icon="flag" tone="bad"/><Kpi label="Open CAPA" value={D.capas.filter(x=>x.stage!=='Closed').length} icon="refresh" tone="warn"/><Kpi label="Audits scheduled" value={D.audits.filter(x=>['Scheduled','Planned'].includes(x.status)).length} icon="check-shield"/><Kpi label="Documents review due" value={D.documents.filter(x=>(new Date(x.review)-D.TODAY)/864e5<=30).length} icon="documents" tone="warn"/><Kpi label="Competency due" value={D.staff.filter(x=>(new Date(x.trainingDue)-D.TODAY)/864e5<=60).length} icon="users" tone="warn"/><Kpi label="Overdue calibrations" value={D.assets.filter(x=>new Date(x.due)<D.TODAY).length} icon="calendar" tone="bad"/><Kpi label="Environment alarms" value={D.envLog.filter(x=>x.temp<18||x.temp>25||x.rh<30||x.rh>60).length} icon="thermometer" tone="bad"/></div><div className="dash-row-2" style={{display:'grid',gridTemplateColumns:'1.5fr 1fr',gap:16,marginBottom:16}}><CardChart icon="trend" title="NCR trend — rolling 12 months"><DVBars data={D.kpis.ncrHistory.map((n,i)=>({k:['Aug','Sep','Oct','Nov','Dec','Jan','Feb','Mar','Apr','May','Jun','Jul'][i],n}))} color="var(--bad)"/></CardChart><InsightCard score={score}>Readiness is reduced by {D.ncrs.filter(x=>x.stage!=='Closed').length} open NCRs and documents approaching review. Recurring template-control issues suggest a targeted document-access audit before the next surveillance visit.</InsightCard></div><CardChart icon="flag" title="Open quality actions"><table className="tbl"><thead><tr><th>Record</th><th>Issue</th><th>Stage</th><th>Owner</th><th>Due</th></tr></thead><tbody>{D.ncrs.filter(x=>x.stage!=='Closed').map(x=><tr key={x.id}><td className="mono cell-strong">{x.id}</td><td>{x.title}</td><td><StatusBadge status={x.stage}/></td><td>{(D.staffById(x.owner)||{}).name}</td><td>{D.fmt(x.due)}</td></tr>)}</tbody></table></CardChart></div>}
function TechnicalDashboard(){const D=DB,me=window.ROLE==='Calibration Technician'?'U-004':null,js=D.jobs.filter(j=>!me||j.tech===me),pending=D.certificates.filter(c=>c.status==='Pending approval').length;return <div className="page page-wide rise"><DashHead title="Technical operations" sub="Workload, execution control, reference standards and certificate review"/><div className="kpi-grid" style={{gridTemplateColumns:'repeat(6,1fr)',marginBottom:16}}><Kpi label="Jobs assigned" value={js.filter(x=>x.tech).length} icon="briefcase"/><Kpi label="Completed" value={js.filter(x=>['Certified','Invoiced','Delivered'].includes(x.stage)).length} icon="check-circle" tone="ok"/><Kpi label="Certs pending approval" value={pending} icon="certificate" tone="warn"/><Kpi label="Equipment waiting" value={D.jobs.filter(x=>['Received','Contract Review','Planned'].includes(x.stage)).reduce((a,x)=>a+x.assets.length,0)} icon="box"/><Kpi label="Intermediate checks due" value={D.standards.filter(x=>(new Date(x.driftCheckDue)-D.TODAY)/864e5<=30).length} icon="gauge" tone="warn"/></div><div className="dash-row-2" style={{display:'grid',gridTemplateColumns:'1.4fr 1fr',gap:16,marginBottom:16}}><CardChart icon="users" title="Workload by technician"><DHBars data={D.staff.filter(s=>s.role==='Calibration Technician').map(s=>({k:s.name,n:D.jobs.filter(j=>j.tech===s.id&&!['Delivered','Certified'].includes(j.stage)).length,c:s.color}))}/></CardChart><InsightCard score={auditReadiness()}>Pressure and electrical queues will peak within four days. Reassign one normal-priority electrical job after competency confirmation; complete STD-TMP-01’s drift check before the next temperature batch.</InsightCard></div><CardChart icon="workflow" title="Execution queue"><table className="tbl"><thead><tr><th>Job</th><th>Customer</th><th>Discipline</th><th>Stage</th><th>Technician</th><th>Due</th></tr></thead><tbody>{js.map(j=><tr key={j.id}><td className="mono cell-strong">{j.id}</td><td>{(D.custById(j.customer)||{}).name}</td><td>{j.discipline.join(', ')}</td><td><StatusBadge status={j.stage}/></td><td>{(D.staffById(j.tech)||{}).name||'Unassigned'}</td><td>{D.fmt(j.due)}</td></tr>)}</tbody></table></CardChart></div>}
function ExecutiveDashboard(){const D=DB,open=D.invoices.filter(x=>x.status!=='Paid'),rev=D.invoices.reduce((a,x)=>a+x.amount,0),pipeline=D.leads.filter(x=>['Won','Quoted'].includes(x.stage)).reduce((a,x)=>a+x.est,0),saudi=Math.round(D.employees.filter(x=>x.nationality==='Saudi').length/D.employees.length*100),training=Math.round(D.employees.filter(x=>new Date(x.trainingDue)>D.TODAY).length/D.employees.length*100),risk=D.contracts.filter(x=>(new Date(x.end)-D.TODAY)/864e5<=60).length;return <div className="page page-wide rise"><DashHead title="Executive command centre" sub="Commercial, operational, quality and workforce performance"/><div className="kpi-grid" style={{gridTemplateColumns:'repeat(5,1fr)',marginBottom:16}}><Kpi label="Revenue YTD" value={rev.toLocaleString()} unit="SAR" icon="receipt" tone="ok"/><Kpi label="Receivables" value={open.reduce((a,x)=>a+(x.total||x.amount),0).toLocaleString()} unit="SAR" icon="trend" tone="warn"/><Kpi label="Gross margin" value="42" unit="%" icon="chart" tone="ok"/><Kpi label="Pipeline value" value={pipeline.toLocaleString()} unit="SAR" icon="briefcase"/><Kpi label="Renewal risk" value={risk} icon="calendar" tone="bad"/><Kpi label="Job TAT vs SLA" value="4.3" unit="/ 5d" icon="clock" tone="ok"/><Kpi label="Throughput MTD" value={D.certificates.length} icon="certificate"/><Kpi label="Open NCR/CAPA" value={D.ncrs.filter(x=>x.stage!=='Closed').length+D.capas.filter(x=>x.stage!=='Closed').length} icon="flag" tone="warn"/><Kpi label="Nitaqat" value={saudi} unit="%" icon="building" tone="ok"/><Kpi label="Training compliance" value={training} unit="%" icon="users" tone="warn"/></div><div className="dash-row-2" style={{display:'grid',gridTemplateColumns:'1.5fr 1fr',gap:16}}><CardChart icon="trend" title="Receivables aging"><DVBars data={['Current','30','60','90+'].map(k=>({k,n:open.filter((x,i)=>['Current','30','60','90+'][i%4]===k).reduce((a,x)=>a+(x.total||x.amount),0)}))}/></CardChart><CardChart icon="sparkles" title="AI-COS executive brief">{D.aicosInsights.slice(0,3).map((x,i)=><div className="lrow" key={i}><span className="ai-badge-ico"><Icon name={x.icon}/></span><div><b>{x.title}</b><div className="faint" style={{fontSize:12}}>{x.detail}</div></div></div>)}</CardChart></div></div>}
function FinanceDashboard(){const D=DB,out=D.invoices.filter(x=>x.status!=='Paid').reduce((a,x)=>a+(x.total||x.amount),0),ap=D.payables.filter(x=>x.status!=='Paid').reduce((a,x)=>a+x.amount,0),vat=D.invoices.reduce((a,x)=>a+x.vat,0);return <div className="page page-wide rise"><DashHead title="Finance dashboard" sub="Cash, collections, supplier exposure and ZATCA VAT"/><div className="kpi-grid" style={{gridTemplateColumns:'repeat(4,1fr)',marginBottom:16}}><Kpi label="Outstanding AR" value={out.toLocaleString()} unit="SAR" icon="trend" tone="warn"/><Kpi label="Open AP" value={ap.toLocaleString()} unit="SAR" icon="receipt" tone="bad"/><Kpi label="Output VAT" value={vat.toLocaleString()} unit="SAR" icon="qr"/><Kpi label="Approved expenses" value={D.expenses.filter(x=>x.status==='Approved').reduce((a,x)=>a+x.amount,0).toLocaleString()} unit="SAR" icon="briefcase"/></div><CardChart icon="chart" title="Budget actual by category"><DHBars data={D.budgets.filter(x=>x.category!=='Total').map(x=>({k:x.category,n:Math.round(x.actual/x.budget*100),c:x.actual>x.budget?'var(--bad)':'var(--primary-600)'}))}/></CardChart></div>}
function SalesDashboard(){const D=DB,pipeline=D.leads.reduce((a,x)=>a+x.est,0),won=D.leads.filter(x=>x.stage==='Won').reduce((a,x)=>a+x.est,0);return <div className="page page-wide rise"><DashHead title="Sales & CRM dashboard" sub="Pipeline, quotations, wins and framework renewals"/><div className="kpi-grid" style={{gridTemplateColumns:'repeat(4,1fr)',marginBottom:16}}><Kpi label="Pipeline" value={pipeline.toLocaleString()} unit="SAR" icon="trend"/><Kpi label="Won" value={won.toLocaleString()} unit="SAR" icon="check-circle" tone="ok"/><Kpi label="Open quotations" value={D.quotations.filter(x=>['Draft','Sent'].includes(x.status)).length} icon="receipt" tone="warn"/><Kpi label="Renewals ≤60d" value={D.contracts.filter(x=>(new Date(x.end)-D.TODAY)/864e5<=60).length} icon="calendar" tone="bad"/></div><CardChart icon="workflow" title="Lead pipeline"><DDonut data={['New','Qualified','Quoted','Won','Lost'].map((k,i)=>({k,n:D.leads.filter(x=>x.stage===k).length,c:['#2f6fed','#0891b2','#c9820a','#15a06b','#df463c'][i]}))} label="LEADS"/></CardChart></div>}
function HRDashboard(){const D=DB,saudi=D.employees.filter(x=>x.nationality==='Saudi').length;return <div className="page page-wide rise"><DashHead title="HR dashboard" sub="Workforce, Saudization, training and leave compliance"/><div className="kpi-grid" style={{gridTemplateColumns:'repeat(4,1fr)',marginBottom:16}}><Kpi label="Employees" value={D.employees.length} icon="users"/><Kpi label="Saudization" value={Math.round(saudi/D.employees.length*100)} unit="%" icon="building" tone="ok"/><Kpi label="Training due ≤60d" value={D.employees.filter(x=>(new Date(x.trainingDue)-D.TODAY)/864e5<=60).length} icon="certificate" tone="warn"/><Kpi label="Leave requests" value={D.leaveRequests.filter(x=>x.status==='Submitted').length} icon="calendar"/></div><CardChart icon="chart" title="Headcount by department"><DHBars data={[...new Set(D.employees.map(x=>x.department))].map(k=>({k,n:D.employees.filter(x=>x.department===k).length}))}/></CardChart></div>}
function RoleDashboard(){if(['Executive Management','System Administrator'].includes(window.ROLE))return <ExecutiveDashboard/>;if(window.ROLE==='Finance Manager')return <FinanceDashboard/>;if(window.ROLE==='Sales / Business Development')return <SalesDashboard/>;if(window.ROLE==='HR Manager')return <HRDashboard/>;if(window.ROLE==='Quality Manager')return <QualityDashboard/>;if(['Calibration Technician','Lab / Technical Manager'].includes(window.ROLE))return <TechnicalDashboard/>;return <ManagementDashboard/>}
Object.assign(window,{DDonut,DVBars,DHBars,DSpark,ManagementDashboard,ExecutiveDashboard,FinanceDashboard,SalesDashboard,HRDashboard,QualityDashboard,TechnicalDashboard,RoleDashboard});
