const {Logo,Icon,Button,IconButton,Card,Stat,StatusPill,Amount,ProgressBar,Tabs,Badge,Alert,Rule}=window.BouwkonsultDesignSystem;
const {FormField,Input,Select,Textarea,Checkbox}=window.BouwkonsultDesignSystem;
const {store,calc,fmt,MockSnelStartService}=window.EG;

function useNow(ms=1000){const [n,setN]=React.useState(Date.now());React.useEffect(()=>{const i=setInterval(()=>setN(Date.now()),ms);return()=>clearInterval(i)},[ms]);return n}
function useStore(){const [,f]=React.useState(0);React.useEffect(()=>store.subscribe(()=>f(x=>x+1)),[]);return store}

/* ---------- statuspil ---------- */
const PILL_STYLE={fout:{background:'var(--danger-100)',color:'var(--danger-600)'}};
function Pill({kind='project',value,style}){
  let label,pill;
  if(kind==='project'){const s=window.EG.projectStatus(value);label=s.label;pill=s.pill}
  else if(kind==='eg'){const s=window.EG.EG_STATUS[value]||window.EG.EG_STATUS.concept;label=s.label;pill=s.pill}
  else {const s=window.EG.SS_STATUS[value]||window.EG.SS_STATUS.niet_verzonden;label=s.label;pill=s.pill}
  const ov=PILL_STYLE[pill];
  return <StatusPill status={pill==='fout'?'herziening':pill} label={label} style={{...(ov||{}),...style}}/>;
}

/* ---------- layoutprimitieven ---------- */
const label12={fontFamily:'var(--font-display)',fontSize:10.5,fontWeight:600,letterSpacing:'.12em',textTransform:'uppercase',color:'var(--ink-600)'};
function PageHead({eyebrow,title,sub,actions,back}){
  return <div style={{display:'flex',justifyContent:'space-between',alignItems:'flex-start',gap:24,marginBottom:28}}>
    <div style={{minWidth:0}}>
      {back?<button onClick={back.onClick} style={{appearance:'none',background:'none',border:0,padding:0,cursor:'pointer',display:'flex',alignItems:'center',gap:6,color:'var(--text-muted)',fontSize:13,marginBottom:10,fontFamily:'var(--font-display)'}}><Icon name="arrow-left" size={14}/>{back.label}</button>:null}
      {eyebrow?<div className="eg-eyebrow" style={{marginBottom:8,fontFamily:'var(--font-mono)',letterSpacing:'.16em'}}>{eyebrow}</div>:null}
      <h1 style={{fontSize:28,lineHeight:1.15,letterSpacing:'-.015em',margin:0}}>{title}</h1>
      {sub?<p style={{marginTop:8,color:'var(--text-muted)',fontSize:14.5,maxWidth:720}}>{sub}</p>:null}
    </div>
    {actions?<div style={{display:'flex',gap:10,alignItems:'center',flex:'none'}}>{actions}</div>:null}
  </div>;
}
function SectionTitle({children,right,style}){
  return <div style={{display:'flex',justifyContent:'space-between',alignItems:'baseline',marginBottom:14,...style}}>
    <h3 style={{fontSize:15.5,margin:0,letterSpacing:'-.005em'}}>{children}</h3>{right}</div>;
}
/* compacte KPI — geen grote dashboardkaart */
function Kpi({label,value,note,onClick,tone,accent}){
  const [h,setH]=React.useState(false);
  return <div onClick={onClick} onMouseEnter={()=>setH(true)} onMouseLeave={()=>setH(false)}
    style={{padding:'14px 18px 16px',background:'var(--white)',border:'1px solid '+(h&&onClick?'var(--teal-600)':'var(--border-hairline)'),
      borderRadius:'var(--radius-md)',borderTop:accent?'2px solid var(--teal-600)':undefined,cursor:onClick?'pointer':'default',
      transition:'border-color 120ms cubic-bezier(.2,0,0,1)',minWidth:0}}>
    <div style={{...label12,fontSize:10,color:'var(--ink-600)'}}>{label}</div>
    <div style={{marginTop:9,fontFamily:'var(--font-display)',fontSize:23,fontWeight:600,letterSpacing:'-.02em',lineHeight:1,
      fontVariantNumeric:'tabular-nums lining-nums',color:tone==='danger'?'var(--danger-600)':'var(--text-strong)'}}>{value}</div>
    {note?<div style={{marginTop:7,fontSize:11.5,color:'var(--text-faint)'}}>{note}</div>:null}
  </div>;
}
function KpiRow({cols=6,children,style}){return <div style={{display:'grid',gridTemplateColumns:'repeat('+cols+',minmax(0,1fr))',gap:16,...style}}>{children}</div>}

/* ---------- tabel ---------- */
function Table({cols,children,style}){
  return <table style={{width:'100%',borderCollapse:'collapse',...style}}><thead><tr>{cols.map((c,i)=>
    <th key={i} style={{...label12,textAlign:c.right?'right':'left',padding:'0 20px 10px',borderBottom:'1px solid var(--ink-300)',whiteSpace:'nowrap',width:c.w}}>{c.label}</th>)}</tr></thead>
    <tbody>{children}</tbody></table>;
}
function Tr({children,onClick,style}){
  const [h,setH]=React.useState(false);
  return <tr onClick={onClick} onMouseEnter={()=>setH(true)} onMouseLeave={()=>setH(false)}
    style={{cursor:onClick?'pointer':'default',background:h&&onClick?'var(--ink-50)':'transparent',transition:'background 120ms cubic-bezier(.2,0,0,1)',...style}}>{children}</tr>;
}
function Td({children,right,mono,muted,style,onClick,colSpan}){
  return <td colSpan={colSpan} onClick={onClick} style={{padding:'13px 20px',borderBottom:'1px solid var(--border-hairline)',fontSize:13.5,verticalAlign:'middle',
    textAlign:right?'right':'left',fontFamily:mono?'var(--font-mono)':undefined,color:muted?'var(--text-faint)':'var(--text-body)',
    fontVariantNumeric:mono?'tabular-nums':undefined,...style}}>{children}</td>;
}
function EmptyState({icon='inbox',title,children,action}){
  return <div style={{padding:'56px 24px',textAlign:'center'}}>
    <Icon name={icon} size={24} color="var(--ink-400)" style={{margin:'0 auto 14px'}}/>
    <div style={{fontFamily:'var(--font-display)',fontSize:15,fontWeight:600,color:'var(--ink-800)'}}>{title}</div>
    {children?<div style={{marginTop:6,fontSize:13.5,color:'var(--text-faint)',maxWidth:380,margin:'6px auto 0'}}>{children}</div>:null}
    {action?<div style={{marginTop:18,display:'flex',justifyContent:'center'}}>{action}</div>:null}
  </div>;
}
function Search({value,onChange,placeholder,width=340}){
  return <div style={{position:'relative',width}}>
    <Icon name="search" size={16} color="var(--ink-500)" style={{position:'absolute',left:12,top:13}}/>
    <Input value={value} placeholder={placeholder} onChange={e=>onChange(e.target.value)} style={{minHeight:40,padding:'9px 12px 9px 36px',fontSize:14}}/></div>;
}
function FilterRow({items,value,onChange}){
  return <div style={{display:'flex',gap:6}}>{items.map(it=>{
    const on=it===value;
    return <button key={it} onClick={()=>onChange(it)} style={{appearance:'none',cursor:'pointer',padding:'7px 13px',borderRadius:'var(--radius-sm)',
      border:'1px solid '+(on?'var(--teal-600)':'var(--border-hairline)'),background:on?'var(--teal-50)':'var(--white)',
      color:on?'var(--teal-800)':'var(--ink-600)',fontFamily:'var(--font-display)',fontSize:13,fontWeight:on?600:500,transition:'all 120ms cubic-bezier(.2,0,0,1)'}}>{it}</button>})}
  </div>;
}
function Toggle({checked,onChange,labels=['Ja','Nee']}){
  return <div style={{display:'flex',alignItems:'center',gap:10}}>
    <button onClick={()=>onChange(!checked)} style={{appearance:'none',border:0,cursor:'pointer',width:42,height:24,borderRadius:999,padding:2,
      background:checked?'var(--teal-600)':'var(--ink-300)',transition:'background 120ms cubic-bezier(.2,0,0,1)'}}>
      <span style={{display:'block',width:20,height:20,borderRadius:'50%',background:'#fff',transform:'translateX('+(checked?18:0)+'px)',transition:'transform 180ms cubic-bezier(.2,0,0,1)'}}/></button>
    <span style={{fontSize:14,color:'var(--text-body)'}}>{checked?labels[0]:labels[1]}</span></div>;
}

/* ---------- overlays ---------- */
function Modal({title,sub,children,footer,onClose,width=520,tone}){
  React.useEffect(()=>{const h=e=>{if(e.key==='Escape')onClose&&onClose()};window.addEventListener('keydown',h);return()=>window.removeEventListener('keydown',h)},[onClose]);
  return <div onClick={onClose} style={{position:'fixed',inset:0,background:'rgba(18,19,20,.42)',zIndex:60,display:'grid',placeItems:'center',padding:32,overflow:'auto'}}>
    <div onClick={e=>e.stopPropagation()} style={{width,maxWidth:'100%',background:'var(--white)',borderRadius:'var(--radius-lg)',boxShadow:'var(--shadow-overlay)',
      borderTop:tone?'3px solid var(--teal-600)':undefined,overflow:'hidden'}}>
      <div style={{padding:'22px 26px 18px',borderBottom:'1px solid var(--border-hairline)',display:'flex',justifyContent:'space-between',gap:16,alignItems:'flex-start'}}>
        <div><h2 style={{fontSize:19,margin:0,letterSpacing:'-.01em'}}>{title}</h2>
          {sub?<div style={{marginTop:6,fontSize:13.5,color:'var(--text-muted)'}}>{sub}</div>:null}</div>
        <button onClick={onClose} aria-label="Sluiten" style={{appearance:'none',background:'none',border:0,cursor:'pointer',padding:4,marginTop:-2}}><Icon name="x" size={18} color="var(--ink-600)"/></button></div>
      <div style={{padding:'22px 26px',maxHeight:'62vh',overflow:'auto'}}>{children}</div>
      {footer?<div style={{padding:'16px 26px',borderTop:'1px solid var(--border-hairline)',background:'var(--ink-50)',display:'flex',justifyContent:'flex-end',gap:10}}>{footer}</div>:null}
    </div></div>;
}
function SidePanel({title,sub,children,footer,onClose,width=520}){
  return <div onClick={onClose} style={{position:'fixed',inset:0,background:'rgba(18,19,20,.42)',zIndex:60}}>
    <div onClick={e=>e.stopPropagation()} style={{position:'absolute',top:0,right:0,bottom:0,width,maxWidth:'100%',background:'var(--white)',
      boxShadow:'var(--shadow-overlay)',display:'flex',flexDirection:'column'}}>
      <div style={{padding:'24px 28px 20px',borderBottom:'1px solid var(--border-hairline)',display:'flex',justifyContent:'space-between',alignItems:'flex-start',gap:16}}>
        <div><h2 style={{fontSize:20,margin:0,letterSpacing:'-.01em'}}>{title}</h2>
          {sub?<div style={{marginTop:6,fontSize:13.5,color:'var(--text-muted)'}}>{sub}</div>:null}</div>
        <button onClick={onClose} aria-label="Sluiten" style={{appearance:'none',background:'none',border:0,cursor:'pointer',padding:4}}><Icon name="x" size={18} color="var(--ink-600)"/></button></div>
      <div style={{flex:1,overflow:'auto',padding:'24px 28px'}}>{children}</div>
      <div style={{padding:'16px 28px',borderTop:'1px solid var(--border-hairline)',background:'var(--ink-50)',display:'flex',justifyContent:'flex-end',gap:10}}>{footer}</div>
    </div></div>;
}
function FormGroup({title,children,cols=2}){
  return <div style={{marginBottom:26}}>
    <div style={{...label12,paddingBottom:10,marginBottom:16,borderBottom:'1px solid var(--border-hairline)'}}>{title}</div>
    <div style={{display:'grid',gridTemplateColumns:'repeat('+cols+',minmax(0,1fr))',gap:16}}>{children}</div></div>;
}
function Toast({toast}){
  if(!toast)return null;
  const tone=toast.tone||'success';
  const c={success:['check-circle','var(--success-600)'],info:['refresh-cw','var(--teal-600)'],danger:['alert-circle','var(--danger-600)']}[tone];
  return <div style={{position:'fixed',bottom:28,left:'50%',transform:'translateX(-50%)',zIndex:80,background:'var(--ink-900)',color:'#fff',
    padding:'13px 20px',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-overlay)',display:'flex',alignItems:'center',gap:12,maxWidth:520}}>
    <Icon name={c[0]} size={17} color={tone==='info'?'var(--teal-300)':tone==='danger'?'#E8A79C':'#8ED3AE'}/>
    <div><div style={{fontFamily:'var(--font-display)',fontSize:14,fontWeight:600}}>{toast.title}</div>
      {toast.detail?<div style={{fontSize:12.5,color:'var(--ink-400)',marginTop:2}}>{toast.detail}</div>:null}</div></div>;
}
/* bron-label: Bouwkonsult of SnelStart */
function Source({from='SnelStart',style}){
  return <span style={{display:'inline-flex',alignItems:'center',gap:5,fontFamily:'var(--font-mono)',fontSize:10.5,letterSpacing:'.08em',
    textTransform:'uppercase',color:'var(--text-faint)',...style}}>
    <span style={{width:4,height:4,borderRadius:'50%',background:from==='SnelStart'?'var(--staal-500)':'var(--brand-geel-diep)'}}/>{from==='SnelStart'?'Uit SnelStart':'Uit Bouwkonsult'}</span>;
}
function DataRow({label,value,note}){
  return <div style={{display:'flex',justifyContent:'space-between',gap:24,padding:'10px 0',borderBottom:'1px solid var(--border-hairline)',fontSize:13.5}}>
    <span style={{color:'var(--text-muted)'}}>{label}</span>
    <span style={{color:'var(--text-strong)',fontWeight:500,textAlign:'right',fontVariantNumeric:'tabular-nums'}}>{value}{note?<div style={{fontWeight:400,fontSize:11.5,color:'var(--text-faint)',marginTop:2}}>{note}</div>:null}</span></div>;
}
/* ---------- medewerker-elementen ---------- */
function Avatar({employee,size=26,style}){
  if(!employee)return null;
  return <span title={employee.name} style={{width:size,height:size,flex:'none',borderRadius:'var(--radius-sm)',background:'var(--ink-100)',
    border:'1px solid var(--ink-200)',display:'inline-grid',placeItems:'center',fontFamily:'var(--font-display)',
    fontSize:size*0.4,fontWeight:700,color:'var(--ink-700)',letterSpacing:'.02em',...style}}>{employee.initials}</span>;
}
function EmployeeCell({id,sub,size=24}){
  const e=calc.employee(id);
  if(!e)return <span style={{color:'var(--text-faint)'}}>—</span>;
  return <span style={{display:'inline-flex',alignItems:'center',gap:9,minWidth:0}}>
    <Avatar employee={e} size={size}/>
    <span style={{minWidth:0}}><span style={{display:'block',color:'var(--ink-900)',fontWeight:500,whiteSpace:'nowrap'}}>{e.name}</span>
      {sub?<span style={{display:'block',fontSize:11.5,color:'var(--text-faint)'}}>{e.role}</span>:null}</span></span>;
}

/* ---------- weekrooster: projecten of medewerkers x dagen ---------- */
const DAY_LABELS=['ma','di','wo','do','vr','za','zo'];
function WeekGrid({weekStart,mode='project',employeeId,onProject,onEmployee}){
  const days=[0,1,2,3,4,5,6].map(i=>window.EG.addDays(weekStart,i));
  const keys=days.map(d=>window.EG.iso(d));
  const today=window.EG.iso(new Date());
  const entries=store.timeEntries.filter(e=>keys.indexOf(e.date)>=0&&(!employeeId||e.employeeId===employeeId));
  const rows=[];
  const add=(key,label,meta)=>{let r=rows.find(x=>x.key===key);
    if(!r){r={key,label,meta,cells:[0,0,0,0,0,0,0],total:0};rows.push(r)}return r};
  if(mode==='employee'){
    store.employees.filter(e=>e.active).forEach(e=>add(e.id,e.name,e));
    entries.forEach(e=>{const r=add(e.employeeId,calc.employeeName(e.employeeId),calc.employee(e.employeeId));
      const c=keys.indexOf(e.date);r.cells[c]+=e.hours;r.total+=e.hours});
  }else{
    entries.forEach(e=>{const p=calc.project(e.projectId);
      const r=add(e.projectId,p?p.name:'Onbekend project',p);
      const c=keys.indexOf(e.date);r.cells[c]+=e.hours;r.total+=e.hours});
    rows.sort((a,b)=>((a.meta&&a.meta.ref)||'')<((b.meta&&b.meta.ref)||'')?1:-1);
  }
  const dayTotals=keys.map((_,i)=>rows.reduce((a,r)=>a+r.cells[i],0));
  const weekTotal=dayTotals.reduce((a,b)=>a+b,0);
  const cell={padding:'11px 10px',borderBottom:'1px solid var(--border-hairline)',fontSize:13.5,textAlign:'right',
    fontFamily:'var(--font-body)',fontVariantNumeric:'tabular-nums'};
  if(!rows.length)return <EmptyState icon="calendar-days" title="Geen uren in deze week">Er zijn deze week nog geen uren op projecten weggeschreven.</EmptyState>;
  /* het signaal 'te weinig geschreven' pas tonen als de week voorbij is */
  const weekDone=window.EG.iso(window.EG.addDays(weekStart,6))<today;
  const expected=weekDone?(Number(store.settings.expectedWeekHours)||0):0;
  return <div style={{overflowX:'auto'}}>
    <table style={{width:'100%',borderCollapse:'collapse',minWidth:760,tableLayout:'fixed'}}>
      <thead><tr>
        <th style={{...label12,textAlign:'left',padding:'0 14px 10px',borderBottom:'1px solid var(--ink-300)',width:'40%'}}>{mode==='employee'?'Medewerker':'Project'}</th>
        {days.map((d,i)=><th key={i} style={{...label12,textAlign:'right',padding:'0 10px 10px',borderBottom:'1px solid var(--ink-300)',width:'7%',
          color:keys[i]===today?'var(--ink-900)':'var(--ink-600)'}}>
          {DAY_LABELS[i]}<div style={{fontFamily:'var(--font-mono)',fontSize:10,fontWeight:400,letterSpacing:0,marginTop:3,
            color:keys[i]===today?'var(--ink-700)':'var(--ink-400)'}}>{d.getDate()}/{d.getMonth()+1}</div></th>)}
        <th style={{...label12,textAlign:'right',padding:'0 14px 10px',borderBottom:'1px solid var(--ink-300)',width:'11%'}}>Totaal</th>
      </tr></thead>
      <tbody>
        {rows.map(r=><Tr key={r.key} onClick={mode==='employee'?(onEmployee?()=>onEmployee(r.meta):undefined):(r.meta&&onProject?()=>onProject(r.meta):undefined)}>
          <Td style={{padding:'11px 14px'}}>
            {mode==='employee'
              ? <span style={{display:'inline-flex',alignItems:'center',gap:10,minWidth:0}}>
                  <Avatar employee={r.meta} size={24}/>
                  <span style={{fontWeight:500,color:'var(--ink-900)',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{r.label}</span>
                  <span style={{fontSize:11.5,color:'var(--text-faint)',whiteSpace:'nowrap'}}>{r.meta?r.meta.role:''}</span></span>
              : <span style={{display:'flex',alignItems:'baseline',gap:10,minWidth:0}}>
                  <span style={{fontFamily:'var(--font-mono)',fontSize:12,color:'var(--text-faint)',flex:'none'}}>{r.meta?r.meta.ref:'—'}</span>
                  <span style={{fontWeight:500,color:'var(--ink-900)',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{r.label}</span></span>}</Td>
          {r.cells.map((v,i)=><td key={i} style={{...cell,background:keys[i]===today?'var(--teal-50)':undefined,
            color:v?'var(--text-body)':'var(--ink-300)'}}>{v?fmt.h(v):'·'}</td>)}
          <td style={{...cell,padding:'11px 14px',fontWeight:600,
            color:mode==='employee'&&expected&&r.total<expected*0.6?'var(--danger-600)':'var(--ink-900)'}}>{fmt.h(r.total)}</td></Tr>)}
        <tr>
          <td style={{padding:'13px 14px',borderTop:'2px solid var(--ink-900)',fontFamily:'var(--font-display)',fontSize:13.5,fontWeight:700}}>Totaal per dag</td>
          {dayTotals.map((v,i)=><td key={i} style={{...cell,borderBottom:0,borderTop:'2px solid var(--ink-900)',fontWeight:700,
            background:keys[i]===today?'var(--teal-50)':undefined,color:v?'var(--ink-900)':'var(--ink-300)'}}>{v?fmt.h(v):'·'}</td>)}
          <td style={{...cell,padding:'13px 14px',borderBottom:0,borderTop:'2px solid var(--ink-900)',fontWeight:700,color:'var(--ink-900)'}}>{fmt.h(weekTotal)}</td></tr>
      </tbody></table></div>;
}
/* weeknavigatie */
function WeekNav({weekStart,onShift,right}){
  const end=window.EG.addDays(weekStart,6);
  return <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',padding:'16px 20px',borderBottom:'1px solid var(--border-hairline)'}}>
    <div style={{display:'flex',alignItems:'center',gap:14}}>
      <IconButton icon="chevron-left" label="Vorige week" onClick={()=>onShift(-1)}/>
      <div style={{textAlign:'center',minWidth:280}}>
        <div style={{fontFamily:'var(--font-display)',fontSize:15,fontWeight:700}}>Week {window.EG.weekNo(weekStart)}</div>
        <div style={{fontSize:12.5,color:'var(--text-faint)',marginTop:2}}>{fmt.longDate(window.EG.iso(weekStart))} t/m {fmt.longDate(window.EG.iso(end))}</div></div>
      <IconButton icon="chevron-right" label="Volgende week" onClick={()=>onShift(1)}/></div>
    {right}</div>;
}
Object.assign(window,{useNow,useStore,Pill,PageHead,SectionTitle,Kpi,KpiRow,Table,Tr,Td,EmptyState,Search,FilterRow,Toggle,Modal,SidePanel,FormGroup,Toast,Source,DataRow,WeekGrid,WeekNav,Avatar,EmployeeCell,label12,
  Logo,Icon,Button,IconButton,Card,Stat,StatusPill,Amount,ProgressBar,Tabs,Badge,Alert,Rule,FormField,Input,Select,Textarea,Checkbox});
