/* =========================================================================
   ui.jsx — shared primitives, icons, app shell
   ========================================================================= */
const { useState:uS, useEffect:uE, useRef:uR } = React;

/* ---------- icons (simple line glyphs) ---------- */
function Icon({ name, size=20, stroke=1.8, className='' }){
  const p = {
    dashboard: <><rect x="3" y="3" width="7" height="9" rx="1"/><rect x="14" y="3" width="7" height="5" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/><rect x="3" y="16" width="7" height="5" rx="1"/></>,
    workers: <><circle cx="9" cy="8" r="3.2"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0"/><path d="M16 7.5a3 3 0 0 1 0 5.6"/><path d="M17.5 20a5.5 5.5 0 0 0-3-4.9"/></>,
    site: <><path d="M3 21h18"/><path d="M5 21V8l7-4 7 4v13"/><path d="M9 21v-5h6v5"/><path d="M9 11h.01M15 11h.01"/></>,
    check: <><rect x="3" y="4" width="18" height="17" rx="2"/><path d="M3 9h18M8 2v4M16 2v4"/><path d="M8.5 14.5l2 2 4-4"/></>,
    clock: <><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></>,
    payroll: <><rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="12" cy="12" r="2.5"/><path d="M7 12h.01M17 12h.01"/></>,
    slip: <><path d="M6 2h9l4 4v16l-2.2-1.3L14.5 22l-2.5-1.3L9.5 22 7 20.7 4.8 22V4a2 2 0 0 1 2-2z" transform="translate(0.5,0)"/><path d="M8 8h8M8 12h8M8 16h5"/></>,
    settings: <><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 0 0-.1-1.3l2-1.5-2-3.4-2.3 1a7 7 0 0 0-2.2-1.3L14 3h-4l-.4 2.2a7 7 0 0 0-2.2 1.3l-2.3-1-2 3.4 2 1.5A7 7 0 0 0 5 12c0 .4 0 .9.1 1.3l-2 1.5 2 3.4 2.3-1a7 7 0 0 0 2.2 1.3L10 21h4l.4-2.2a7 7 0 0 0 2.2-1.3l2.3 1 2-3.4-2-1.5c.1-.4.1-.9.1-1.3z"/></>,
    plus: <><path d="M12 5v14M5 12h14"/></>,
    edit: <><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></>,
    trash: <><path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v5M14 11v5"/></>,
    print: <><path d="M6 9V3h12v6M6 18H4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="7" rx="1"/></>,
    search: <><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></>,
    money: <><circle cx="12" cy="12" r="9"/><path d="M12 6v12M9.5 9.5a2.5 2.5 0 0 1 5 0c0 1.5-1.2 1.8-2.5 2.2-1.3.4-2.5.7-2.5 2.3a2.5 2.5 0 0 0 5 0"/></>,
    arrow: <><path d="M5 12h14M13 6l6 6-6 6"/></>,
    chevdown: <><path d="m6 9 6 6 6-6"/></>,
    close: <><path d="M6 6l12 12M18 6 6 18"/></>,
    logout: <><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="M16 17l5-5-5-5M21 12H9"/></>,
    pin: <><path d="M12 21s7-6.3 7-11a7 7 0 1 0-14 0c0 4.7 7 11 7 11z"/><circle cx="12" cy="10" r="2.5"/></>,
    calendar: <><rect x="3" y="4" width="18" height="17" rx="2"/><path d="M3 9h18M8 2v4M16 2v4"/></>,
    bolt: <><path d="M13 2 4 14h7l-1 8 9-12h-7l1-8z"/></>,
    phone: <><path d="M5 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L20 13l2 4v3a1 1 0 0 1-1 1A17 17 0 0 1 4 5a1 1 0 0 1 1-1z"/></>,
    user: <><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></>,
    lock: <><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></>,
    menu: <><path d="M3 6h18M3 12h18M3 18h18"/></>,
    download: <><path d="M12 3v12m0 0 4-4m-4 4-4-4M4 19h16"/></>,
    warn: <><path d="M12 3 2 20h20L12 3z"/><path d="M12 10v4M12 17h.01"/></>,
    helmet: <><path d="M3 16a9 9 0 0 1 18 0"/><path d="M2 16h20v2a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-2z"/><path d="M9 8.5C9 6 10.5 4.5 12 4.5S15 6 15 8.5"/></>,
    shop: <><path d="M4 9h16l-1-5H5L4 9z"/><path d="M4 9v10a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V9"/><path d="M9 20v-6h6v6"/></>,
    fuel: <><rect x="4" y="3" width="10" height="18" rx="1.5"/><path d="M4 11h10"/><path d="M14 7l3 3v7a2 2 0 0 0 4 0V9l-3-3"/></>,
    chart: <><path d="M3 3v18h18"/><rect x="7" y="11" width="3" height="6"/><rect x="12" y="7" width="3" height="10"/><rect x="17" y="13" width="3" height="4"/></>,
    camera: <><path d="M3 8a2 2 0 0 1 2-2h2l1.5-2h7L19 6h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" transform="translate(-1,0)"/><circle cx="11" cy="13" r="3.5"/></>,
    target: <><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></>,
    history: <><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 4v4h4"/><path d="M12 8v4l3 2"/></>,
    trend: <><path d="M3 17l6-6 4 4 7-7"/><path d="M17 8h4v4"/></>,
    fire: <><path d="M12 2s5 4 5 9a5 5 0 0 1-10 0c0-1.5.5-2.5 1-3 0 1.5 1 2 1.5 2 .5-2-1-3.5 2.5-8z"/></>,
  }[name] || null;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
      strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" className={className} aria-hidden>
      {p}
    </svg>
  );
}

/* ---------- Button ---------- */
function Button({ children, variant='primary', size='md', icon, iconR, className='', ...rest }){
  const base = 'tap inline-flex items-center justify-center gap-2 font-display font-semibold rounded-lg whitespace-nowrap select-none disabled:opacity-40 disabled:pointer-events-none';
  const sizes = { sm:'text-sm px-3 py-1.5', md:'text-[15px] px-4 py-2.5', lg:'text-base px-5 py-3' };
  const vars = {
    primary: 'bg-brand text-ink hover:bg-brand-hi shadow-[0_6px_18px_-6px_rgba(232,133,43,0.6)]',
    dark:    'bg-raised text-chalk border border-line hover:border-haze/60',
    ghost:   'text-haze hover:text-chalk hover:bg-raised',
    danger:  'bg-bad/15 text-bad border border-bad/40 hover:bg-bad/25',
    hazard:  'bg-hazard text-ink hover:brightness-110',
  };
  return (
    <button className={`${base} ${sizes[size]} ${vars[variant]} ${className}`} {...rest}>
      {icon && <Icon name={icon} size={size==='sm'?16:18} />}
      {children}
      {iconR && <Icon name={iconR} size={size==='sm'?16:18} />}
    </button>
  );
}

/* ---------- Card ---------- */
function Card({ children, className='', pad=true }){
  return <div className={`bg-panel border border-line rounded-xl ${pad?'p-5':''} ${className}`}>{children}</div>;
}

/* ---------- Badge ---------- */
function Badge({ children, tone='brand', soft=true, className='' }){
  const map = {
    brand:'text-brand bg-brand/12 border-brand/30',
    hazard:'text-hazard bg-hazard/12 border-hazard/30',
    ok:'text-ok bg-ok/12 border-ok/30',
    warn:'text-warn bg-warn/12 border-warn/30',
    bad:'text-bad bg-bad/12 border-bad/30',
    haze:'text-haze bg-white/5 border-line',
  };
  return <span className={`inline-flex items-center gap-1 text-xs font-semibold px-2 py-0.5 rounded-md border whitespace-nowrap ${map[tone]} ${className}`}>{children}</span>;
}

function TypeBadge({ type }){ const t=TYPE[type]; return <Badge tone={t.tone}>{t.short}</Badge>; }

/* ---------- Field / Input ---------- */
function Field({ label, children, hint, req=false, className='' }){
  return (
    <label className={`block ${className}`}>
      {label && <div className="text-[13px] font-medium text-haze mb-1.5">{label}{req && <span className="text-bad ml-0.5">*</span>}</div>}
      {children}
      {hint && <div className="text-xs text-haze/70 mt-1">{hint}</div>}
    </label>
  );
}
const inputCls = 'w-full bg-ink border border-line rounded-lg px-3.5 py-2.5 text-chalk placeholder:text-haze/50 focus:outline-none focus:border-brand focus:ring-1 focus:ring-brand/40 transition';
function Input(props){ return <input {...props} className={`${inputCls} ${props.className||''}`} />; }
function Select({ children, ...p }){ return (
  <div className="relative">
    <select {...p} className={`${inputCls} appearance-none pr-9 ${p.className||''}`}>{children}</select>
    <div className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-haze"><Icon name="chevdown" size={16}/></div>
  </div>
);}

/* ---------- NumberInput: ลูกศรขึ้น/ลง + คลิกแล้วเลือกทั้งหมด (พิมพ์ทับได้ ไม่ติด 0) ---------- */
function NumberInput({ value, onChange, min=0, max=Infinity, step=1, placeholder='0', blankZero=false, className='' }){
  const show = (v)=> (blankZero && !v) ? '' : ((v===0||v) ? String(v) : '');
  const [text,setText] = uS(show(value));
  const focused = uR(false);
  uE(()=>{ if(!focused.current) setText(show(value)); }, [value]);
  const emit = (v)=>{ if(v===''||v==='.'){ onChange(0); return; } const n=Number(v); if(!isNaN(n)) onChange(Math.min(max,Math.max(min,n))); };
  const bump = (d)=>{ let n=(Number(text)||0)+d*step; n=Math.min(max,Math.max(min,n)); setText(String(n)); onChange(n); };
  return (
    <div className={`flex items-stretch bg-ink border border-line rounded-lg overflow-hidden focus-within:border-brand focus-within:ring-1 focus-within:ring-brand/40 transition ${className}`}>
      <input value={text} inputMode="decimal" placeholder={placeholder}
        onFocus={e=>{ focused.current=true; e.target.select(); }}
        onBlur={()=>{ focused.current=false; setText(show(value)); }}
        onChange={e=>{ const v=e.target.value.replace(/[^0-9.]/g,''); setText(v); emit(v); }}
        className="num flex-1 min-w-0 bg-transparent px-3.5 py-2.5 text-chalk placeholder:text-haze/50 focus:outline-none"/>
      <div className="flex flex-col shrink-0 border-l border-line">
        <button type="button" tabIndex={-1} onClick={()=>bump(1)} className="tap flex-1 px-2.5 text-haze hover:text-brand hover:bg-white/5 flex items-center justify-center"><Icon name="chevdown" size={13} className="rotate-180"/></button>
        <button type="button" tabIndex={-1} onClick={()=>bump(-1)} className="tap flex-1 px-2.5 text-haze hover:text-brand hover:bg-white/5 flex items-center justify-center border-t border-line"><Icon name="chevdown" size={13}/></button>
      </div>
    </div>
  );
}

/* ---------- Modal ---------- */
function Modal({ open, onClose, title, children, footer, wide=false }){
  uE(()=>{ if(!open) return; const h=e=>e.key==='Escape'&&onClose(); window.addEventListener('keydown',h); return ()=>window.removeEventListener('keydown',h); },[open,onClose]);
  if(!open) return null;
  return (
    <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center p-0 sm:p-6 no-print">
      <div className="absolute inset-0 bg-black/70 backdrop-blur-sm" onClick={onClose}></div>
      <div className={`relative bg-panel border border-line rounded-t-2xl sm:rounded-2xl shadow-pop w-full ${wide?'max-w-3xl':'max-w-lg'} max-h-[92vh] flex flex-col`}>
        <div className="flex items-center justify-between px-5 py-4 border-b border-line">
          <h3 className="font-display font-bold text-lg">{title}</h3>
          <button onClick={onClose} className="tap text-haze hover:text-chalk p-1"><Icon name="close"/></button>
        </div>
        <div className="px-5 py-5 overflow-y-auto">{children}</div>
        {footer && <div className="px-5 py-4 border-t border-line flex justify-end gap-2">{footer}</div>}
      </div>
    </div>
  );
}

/* ---------- Stat ---------- */
function Stat({ label, value, sub, icon, tone='brand', strip=false }){
  const tones = { brand:'text-brand', hazard:'text-hazard', ok:'text-ok', bad:'text-bad', chalk:'text-chalk' };
  return (
    <Card className="relative overflow-hidden grain">
      {strip && <div className="absolute top-0 left-0 right-0 h-1 brand-strip opacity-80"></div>}
      <div className="flex items-start justify-between">
        <div>
          <div className="text-[13px] text-haze font-medium">{label}</div>
          <div className={`font-display font-bold text-3xl mt-1.5 num ${tones[tone]}`}>{value}</div>
          {sub && <div className="text-xs text-haze mt-1">{sub}</div>}
        </div>
        {icon && <div className={`shrink-0 w-11 h-11 rounded-lg bg-white/5 border border-line flex items-center justify-center ${tones[tone]}`}><Icon name={icon} size={22}/></div>}
      </div>
    </Card>
  );
}

/* ---------- Empty ---------- */
function Empty({ icon='search', title, sub, action }){
  return (
    <div className="text-center py-16 px-6">
      <div className="mx-auto w-14 h-14 rounded-xl bg-raised border border-line flex items-center justify-center text-haze mb-4"><Icon name={icon} size={26}/></div>
      <div className="font-display font-semibold text-lg">{title}</div>
      {sub && <div className="text-haze text-sm mt-1 max-w-sm mx-auto">{sub}</div>}
      {action && <div className="mt-5">{action}</div>}
    </div>
  );
}

/* ---------- Avatar (รองรับรูปถ่าย) ---------- */
function Avatar({ name, photo, size=40, className='' }){
  const initials = (name||'?').trim().slice(0,1);
  const hues = ['#E8852B','#3fae6e','#F4C542','#5b8def','#c96e1d'];
  const h = hues[(name||'').length % hues.length];
  if(photo) return (
    <img src={photo} alt={name} className={`rounded-lg object-cover shrink-0 ${className}`} style={{ width:size, height:size }} />
  );
  return (
    <div className={`rounded-lg font-display font-bold flex items-center justify-center shrink-0 text-ink ${className}`}
      style={{ width:size, height:size, background:h, fontSize:size*0.42 }}>{initials}</div>
  );
}

/* ---------- Section header ---------- */
function PageHead({ title, sub, actions }){
  return (
    <div className="flex flex-wrap items-end justify-between gap-3 mb-6">
      <div>
        <h1 className="font-display font-extrabold text-2xl sm:text-[28px] leading-tight tracking-tight">{title}</h1>
        {sub && <p className="text-haze text-sm mt-1">{sub}</p>}
      </div>
      {actions && <div className="flex gap-2">{actions}</div>}
    </div>
  );
}

/* ---------- Month / Period picker ---------- */
function MonthPicker({ value, onChange }){
  const [y,m] = value.split('-').map(Number);
  const opts = [];
  for(let i=0;i<8;i++){ const d=new Date(TODAY.getFullYear(),TODAY.getMonth()-i,1); opts.push(ym(d)); }
  return (
    <Select value={value} onChange={e=>onChange(e.target.value)} className="!py-2 min-w-[170px]">
      {opts.map(o=> <option key={o} value={o}>{thaiMonthLabel(o)}</option>)}
    </Select>
  );
}

function PeriodPicker({ value, onChange }){
  const periods = listPeriods(8);
  return (
    <Select value={value?.id} onChange={e=>onChange(periods.find(p=>p.id===e.target.value))} className="!py-2 min-w-[280px]">
      {periods.map(p=> <option key={p.id} value={p.id}>{p.label} · {p.range}</option>)}
    </Select>
  );
}

/* ---------- grouped work-type select ---------- */
function WorkTypeSelect({ value, onChange, placeholder='— เลือกประเภทงาน —', ...p }){
  const types = (window.__workTypes || WORK_TYPES).filter(t=>t.active!==0);
  return (
    <Select value={value||''} onChange={e=>onChange(e.target.value)} {...p}>
      <option value="">{placeholder}</option>
      {WORK_GROUPS.map(g=>{
        const list = types.filter(t=>(t.group||t.grp)===g.key);
        if(list.length===0) return null;
        return (
          <optgroup key={g.key} label={g.th}>
            {list.map(t=>(
              <option key={t.id} value={t.id}>{t.name}</option>
            ))}
          </optgroup>
        );
      })}
    </Select>
  );
}

/* ---------- progress bar ---------- */
function Progress({ value, max, tone='brand', height=8 }){
  const pct = max>0 ? Math.min(100, (value/max)*100) : 0;
  const over = max>0 && value>max;
  const color = over ? 'bg-bad' : (pct>85 ? 'bg-warn' : (tone==='brand'?'bg-brand':tone==='ok'?'bg-ok':'bg-hazard'));
  return (
    <div className="rounded-full bg-ink overflow-hidden" style={{height}}>
      <div className={`h-full ${color} transition-all`} style={{width:`${pct}%`}}></div>
    </div>
  );
}

Object.assign(window, {
  Icon, Button, Card, Badge, TypeBadge, Field, Input, Select, NumberInput, Modal,
  Stat, Empty, Avatar, PageHead, MonthPicker, PeriodPicker, WorkTypeSelect, Progress, inputCls,
});
