// workorder.jsx — Work Order detail (the product core: tickets + running total).
const { useState: useS, useMemo, useRef: useR, useEffect: useE } = React;

function TicketCard({ t, onApprove, onDecline, onRepropose, onAttach, onSendChat }) {
  const meta = TICKET_TYPES[t.type];
  const [chatOpen, setChatOpen] = useS(t.status === 'declined');
  const [draft, setDraft] = useS('');
  const needsReceipt = t.type === 'order';
  const needsPhoto = true;
  const hasReceipt = !!t.receipt;
  const hasPhoto = t.photos.length > 0;
  const missingReq = (t.status === 'approved' || t.status === 'proposed') &&
    ((needsReceipt && !hasReceipt) || (needsPhoto && !hasPhoto));

  return (
    <div className={`ticket ${t.status === 'proposed' ? 'proposed' : ''}`}>
      <div className="ticket-hd">
        <div className={`ticket-type ${meta.cls}`}>{React.createElement(Icon[meta.icon], { size: 17 })}</div>
        <div className="ticket-body">
          <div className="between" style={{ alignItems: 'flex-start' }}>
            <div>
              <div className="ticket-title">{tx(t.title)}</div>
              <div className="row" style={{ gap: 7, marginTop: 5 }}>
                <Badge kind="outline">{tx(meta.label)}</Badge>
                <span className="tiny muted">{t.id} · {tx('by')} {teamById(t.author)?.name.split(' ')[0]}</span>
              </div>
            </div>
            <div style={{ textAlign: 'right', flexShrink: 0, whiteSpace: 'nowrap' }}>
              <div className="ticket-price">+{zl(displayed(t.net))}</div>
              <div className="tiny muted" style={{ marginTop: 1 }}>{tx('net')} {zl(t.net)}</div>
            </div>
          </div>
          <div className="ticket-desc">{tx(t.desc)}</div>

          {/* attachments */}
          <div className="thumbs">
            {t.photos.map((p, i) => <Thumb key={i} label={p.label} />)}
            {needsReceipt && (
              hasReceipt
                ? <div className="thumb" title="receipt">{React.createElement(Icon.receipt, { size: 15 })}</div>
                : <div className="thumb req missing" onClick={() => onAttach(t.id, 'receipt')} style={{ cursor: 'pointer' }}>
                    {React.createElement(Icon.receipt, { size: 14 })}<span style={{ marginTop: 2 }}>{tx('receipt req.')}</span>
                  </div>
            )}
            {!hasPhoto && (
              <div className="thumb req missing" onClick={() => onAttach(t.id, 'photo')} style={{ cursor: 'pointer' }}>
                {React.createElement(Icon.camera, { size: 14 })}<span style={{ marginTop: 2 }}>{tx('photo req.')}</span>
              </div>
            )}
            <div className="thumb req" onClick={() => onAttach(t.id, 'photo')} style={{ cursor: 'pointer' }}>
              {React.createElement(Icon.plus, { size: 14 })}
            </div>
          </div>
        </div>
      </div>

      {/* status / actions foot */}
      <div className="ticket-foot">
        {t.status === 'proposed' && (
          <>
            <Badge kind="accent" pip>{tx('Awaiting client')}</Badge>
            {missingReq && <span className="tiny" style={{ color: 'var(--danger)' }}>· {fmt('{req} missing', { req: tx(meta.req) })}</span>}
            <span className="spacer" />
            <span className="tiny muted">{tx('Simulate client:')}</span>
            <button className="btn sm btn-success" onClick={() => onApprove(t.id)}>
              {React.createElement(Icon.check, { size: 14, stroke: 2.6 })} {tx('Approve')}
            </button>
            <button className="btn sm btn-danger" onClick={() => { onDecline(t.id); setChatOpen(true); }}>
              {React.createElement(Icon.x, { size: 14, stroke: 2.6 })} {tx('Decline')}
            </button>
          </>
        )}
        {t.status === 'approved' && (
          <>
            <Badge kind="success" pip>{tx('Approved · added to total')}</Badge>
            {missingReq
              ? <span className="tiny" style={{ color: 'var(--danger)' }}>· {fmt('{req} missing — blocks “Ready”', { req: tx(meta.req) })}</span>
              : <span className="tiny muted">· {tx('attachments complete')}</span>}
          </>
        )}
        {t.status === 'declined' && (
          <>
            <Badge kind="danger" pip>{tx('Declined by client')}</Badge>
            <span className="spacer" />
            <button className="btn sm btn-ghost" onClick={() => setChatOpen((v) => !v)}>
              {React.createElement(Icon.chat, { size: 14 })} {chatOpen ? tx('Hide chat') : tx('Open chat')}
            </button>
            <button className="btn sm btn-outline" onClick={() => onRepropose(t.id)}>{tx('Re-propose')}</button>
          </>
        )}
      </div>

      {/* chat thread on decline */}
      {t.status === 'declined' && chatOpen && (
        <div style={{ borderTop: '1px solid var(--border)' }}>
          <div className="chat">
            {t.chat.length === 0 && <div className="tiny muted" style={{ textAlign: 'center', padding: '4px 0' }}>{tx('Client declined. Explain why the work is needed or propose a different scope — price only goes up from the “from” floor.')}</div>}
            {t.chat.map((m, i) => (
              <div key={i} className={`msg ${m.me ? 'me' : 'them'}`}>
                <div className="who">{m.me ? tx('You · shop') : 'Marek · ' + tx('client')}</div>
                {m.text}
              </div>
            ))}
          </div>
          <div className="chat-input">
            <input className="input" placeholder={tx('Explain or propose another scope…')} value={draft}
              onChange={(e) => setDraft(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter' && draft.trim()) { onSendChat(t.id, draft.trim()); setDraft(''); } }} />
            <button className="btn btn-primary" disabled={!draft.trim()}
              onClick={() => { onSendChat(t.id, draft.trim()); setDraft(''); }}>{tx('Send')}</button>
          </div>
        </div>
      )}
    </div>
  );
}

function NewTicketModal({ onClose, onCreate }) {
  const [type, setType] = useS('extra');
  const [title, setTitle] = useS('');
  const [desc, setDesc] = useS('');
  const [price, setPrice] = useS('');
  const meta = TICKET_TYPES[type];
  const valid = title.trim() && price && Number(price) > 0;
  return (
    <Modal title={tx('New ticket')} sub={tx('Additional work or part discovered during the repair')} onClose={onClose}
      footer={<>
        <button className="btn btn-ghost" onClick={onClose}>{tx('Cancel')}</button>
        <button className="btn btn-primary" disabled={!valid}
          onClick={() => onCreate({ type, title: title.trim(), desc: desc.trim(), net: Number(price) })}>
          {tx('Send to client for approval')}
        </button>
      </>}>
      <div className="field">
        <label>{tx('Ticket type')}</label>
        <div className="wrap">
          {Object.entries(TICKET_TYPES).map(([k, m]) => (
            <button key={k} className={`btn ${type === k ? 'btn-primary' : 'btn-outline'} sm`} onClick={() => setType(k)}>
              {React.createElement(Icon[m.icon], { size: 14 })} {tx(m.label)}
            </button>
          ))}
        </div>
        <div className="hint">{tx('Required on completion:')} <b>{tx(meta.req)}</b></div>
      </div>
      <div className="field">
        <label>{tx('Title')}</label>
        <input className="input" placeholder={tx('e.g. Replace front brake discs')} value={title} onChange={(e) => setTitle(e.target.value)} autoFocus />
      </div>
      <div className="field">
        <label>{tx('Description for the client')}</label>
        <textarea className="textarea" placeholder={tx('Explain what was found and why the work is needed…')} value={desc} onChange={(e) => setDesc(e.target.value)} />
      </div>
      <div className="field" style={{ marginBottom: 4 }}>
        <label>{tx('Net price (shop)')}</label>
        <div className="row" style={{ gap: 14 }}>
          <div className="input-money" style={{ width: 160 }}>
            <span>zł</span>
            <input className="input" type="number" placeholder="0" value={price} onChange={(e) => setPrice(e.target.value)} />
          </div>
          {price > 0 && (
            <div className="tiny muted">
              {tx('Client sees')} <b className="mono" style={{ color: 'var(--text)' }}>{zl(displayed(Number(price)))}</b>
              <span> · {fmt('incl. {n}% platform fee {fee}', { n: Math.round(TAKE_RATE * 100), fee: zl(fee(Number(price))) })}</span>
            </div>
          )}
        </div>
      </div>
    </Modal>
  );
}

function AssignModal({ assigned, onClose, onSave }) {
  const [selected, setSelected] = useS(assigned);
  const toggle = (id) => setSelected((xs) => xs.includes(id) ? xs.filter((x) => x !== id) : [...xs, id]);
  const members = teamCatalog().filter((u) => u.active !== false);
  return (
    <Modal title={tx('Assign')} sub={tx('Select staff assigned to this work order')} onClose={onClose}
      footer={<>
        <button className="btn btn-ghost" onClick={onClose}>{tx('Cancel')}</button>
        <button className="btn btn-primary" disabled={selected.length === 0} onClick={() => onSave(selected)}>{React.createElement(Icon.check, { size: 15, stroke: 2.6 })} {tx('Save assignment')}</button>
      </>}>
      <div className="col" style={{ gap: 8 }}>
        {members.map((u) => {
          const on = selected.includes(u.id);
          return (
            <div className="list-item clickable" key={u.id} onClick={() => toggle(u.id)} style={{ border: '1px solid var(--border)', borderRadius: 'var(--r)', padding: '12px 14px' }}>
              <Avatar name={u.name} accent={on} />
              <div style={{ flex: 1 }}><div className="strong sec">{u.name}</div><div className="tiny muted">{tx(u.role)} · {tx(u.spec)}</div></div>
              {on ? <Badge kind="success">{React.createElement(Icon.check, { size: 11, stroke: 3 })} {tx('Assigned')}</Badge> : <Badge kind="outline">{tx('Available')}</Badge>}
            </div>
          );
        })}
      </div>
    </Modal>
  );
}

function normalizeOrderForDetail(orderId) {
  const orders = readStored('ac.workOrders', WORK_ORDERS);
  const found = orders.find((w) => w.id === orderId) || (orderId === HERO.id ? HERO : orders[0] || HERO);
  return {
    ...HERO,
    ...found,
    vehicle: { ...HERO.vehicle, ...(found.vehicle || {}) },
    services: found.services || HERO.services,
    assigned: found.assigned && found.assigned.length ? found.assigned : HERO.assigned,
    tickets: found.id === HERO.id ? HERO.tickets : [],
  };
}

function WorkOrderView({ orderId = HERO.id, onBack }) {
  const initialOrder = normalizeOrderForDetail(orderId);
  const ticketFallback = initialOrder.id === HERO.id ? readStored('ac.heroTickets', HERO.tickets) : [];
  const orderFallback = initialOrder.id === HERO.id ? readStored('ac.heroOrder', initialOrder) : initialOrder;
  const [order, setOrder] = useStoredState(`ac.workOrder.${initialOrder.id}`, orderFallback);
  const [tickets, setTickets] = useStoredState(`ac.workOrder.${initialOrder.id}.tickets`, ticketFallback);
  const [method, setMethod] = useStoredState(`ac.workOrder.${initialOrder.id}.method`, initialOrder.method);
  const [status, setStatus] = useStoredState(`ac.workOrder.${initialOrder.id}.status`, initialOrder.status);
  const [showNew, setShowNew] = useS(false);
  const [showAssign, setShowAssign] = useS(false);
  const [collected, setCollected] = useS('');
  const [bumpKey, setBumpKey] = useS(0);

  const baseNet = order.services.reduce((a, id) => a + (svc(id)?.net || 0), 0);
  const baseDisp = order.services.reduce((a, id) => a + displayed(svc(id)?.net || 0), 0);
  const approved = tickets.filter((t) => t.status === 'approved');
  const ticketsDisp = approved.reduce((a, t) => a + displayed(t.net), 0);
  const ticketsNet = approved.reduce((a, t) => a + t.net, 0);
  const grand = baseDisp + ticketsDisp;
  const netTotal = baseNet + ticketsNet;
  const commission = grand - netTotal;

  useE(() => {
    patchStored('ac.workOrders', WORK_ORDERS, (orders) => orders.map((w) => w.id === order.id ? {
      ...w,
      assigned: order.assigned,
      method,
      status,
      ticketsCount: tickets.length,
      ticketsApproved: tickets.filter((t) => t.status === 'approved').length,
      ticketsNet: tickets.filter((t) => t.status === 'approved').reduce((sum, t) => sum + t.net, 0),
    } : w));
  }, [order.assigned.join(','), method, status, tickets]);

  // gate: every approved ticket must have its required attachment
  const blocked = approved.filter((t) => (t.type === 'order' ? (!t.receipt || t.photos.length === 0) : t.photos.length === 0));
  const canReady = status === 'in_progress' && blocked.length === 0;

  const upd = (id, fn) => setTickets((ts) => ts.map((t) => (t.id === id ? fn({ ...t }) : t)));

  const approveT = (id) => { upd(id, (t) => (t.status = 'approved', t)); setBumpKey((k) => k + 1); toast(tx('Client approved — added to total'), 'checkCircle'); };
  const declineT = (id) => { upd(id, (t) => (t.status = 'declined', t.chat = [{ me: false, text: tx('I’d rather skip this for now — is it really necessary?') }], t)); toast(tx('Client declined — chat opened'), 'chat'); };
  const reproposeT = (id) => { upd(id, (t) => (t.status = 'proposed', t)); toast(tx('Ticket re-proposed to client'), 'arrowR'); };
  const attach = (id, kind) => {
    upd(id, (t) => {
    if (kind === 'receipt') t.receipt = { label: 'receipt' };
    else t.photos = [...t.photos, { label: 'photo' }];
    return t;
    });
    toast(kind === 'receipt' ? tx('Receipt attached') : tx('Photo attached'), kind === 'receipt' ? 'receipt' : 'camera');
  };
  const sendChat = (id, text) => upd(id, (t) => (t.chat = [...t.chat, { me: true, text }], t));
  const mergeApiOrder = (apiOrder) => {
    if (!apiOrder) return;
    setOrder((current) => ({
      ...current,
      ...apiOrder,
      services: apiOrder.services || current.services,
      assigned: apiOrder.assigned || current.assigned,
      vehicle: apiOrder.vehicle || current.vehicle,
      opened: apiOrder.opened || current.opened,
    }));
    if (apiOrder.method) setMethod(apiOrder.method);
    if (apiOrder.status) setStatus(apiOrder.status);
  };

  const createT = async ({ type, title, desc, net }) => {
    const id = 'T-' + String(tickets.length + 1).padStart(2, '0');
    const draft = { id, type, title, desc, author: 'u1', net, status: 'proposed', photos: [], receipt: null, chat: [] };
    const apiTicket = await AutoCareAPI.createTicket(order.id, draft).catch((e) => (console.warn('[AutoCareAPI] ticket create failed', e), null));
    setTickets((ts) => [...ts, apiTicket || draft]);
    setShowNew(false);
    toast(apiTicket ? tx('Ticket sent to client and synced') : tx('Ticket sent to client for approval'), 'arrowR');
  };

  const markReady = async () => {
    const apiOrder = await AutoCareAPI.markReady(order.id).catch((e) => (console.warn('[AutoCareAPI] mark ready failed', e), null));
    if (apiOrder) mergeApiOrder(apiOrder);
    else setStatus('ready');
    toast(tx('Customer notified: “Your car is ready”'), 'bell');
  };
  const recordCash = async () => {
    const value = Number(collected) > 0 ? Number(collected) : grand;
    await AutoCareAPI.recordCash(order.id, value).catch((e) => console.warn('[AutoCareAPI] cash payment failed', e));
    setStatus('paid');
    toast(fmt('Cash payment recorded · {amt}', { amt: zl(value) }), 'cash');
  };
  const capture = async () => {
    await AutoCareAPI.captureCard(order.id).catch((e) => console.warn('[AutoCareAPI] card capture failed', e));
    setStatus('paid');
    toast(fmt('Card captured · {amt}', { amt: zl(grand) }), 'card');
  };
  const saveAssign = async (ids) => {
    const apiOrder = await AutoCareAPI.assignWorkOrder(order.id, ids).catch((e) => (console.warn('[AutoCareAPI] assign failed', e), null));
    if (apiOrder) mergeApiOrder(apiOrder);
    else setOrder((o) => ({ ...o, assigned: ids }));
    setShowAssign(false);
    toast(tx('Assignment updated'), 'users');
  };

  return (
    <div className="page view-fade" data-screen-label="Work order detail">
      <div className="breadcrumb">
        <a onClick={onBack}>{tx('Work orders')}</a>{React.createElement(Icon.chevR, { size: 13 })}
        <span className="mono" style={{ color: 'var(--text-2)' }}>{order.id}</span>
      </div>

      {/* header */}
      <div className="between" style={{ alignItems: 'flex-start', marginBottom: 16 }}>
        <div className="row" style={{ gap: 14, alignItems: 'center' }}>
          <div className="veh-ic" style={{ width: 46, height: 46 }}>{React.createElement(Icon.car, { size: 24 })}</div>
          <div>
            <div className="row" style={{ gap: 10 }}>
              <h1 className="page-title" style={{ fontSize: 21 }}>{order.vehicle.make} {order.vehicle.model}</h1>
              <span className="plate" style={{ fontSize: 12 }}>{order.vehicle.plate}</span>
            </div>
            <div className="page-sub" style={{ marginTop: 4 }}>
              {order.id} · {order.customer} · {tx('opened')} {tdate(order.opened)}
            </div>
          </div>
        </div>
        <div className="row" style={{ gap: 8 }}>
          <PayBadge method={method} />
          <StatusBadge status={status} />
        </div>
      </div>

      {/* pipeline */}
      <div className="card card-pad" style={{ marginBottom: 20, overflowX: 'auto' }}>
        <Pipeline status={status} />
      </div>

      <div className="two-col">
        {/* LEFT — work & tickets */}
        <div className="col" style={{ gap: 18 }}>
          {/* base services */}
          <div className="card">
            <div className="card-hd"><h3>{tx('Base work order')}</h3><span className="spacer" />
              <span className="tiny muted">{tx('price “from” floor · cannot decrease')}</span></div>
            {order.services.map((id) => {
              const s = svc(id) || { name: id, cat: 'Service', dur: '—', net: 0 };
              return (
                <div className="list-item" key={id}>
                  <div className="veh-ic" style={{ width: 32, height: 32 }}>{React.createElement(Icon.wrench, { size: 16 })}</div>
                  <div style={{ flex: 1 }}>
                    <div className="strong sec">{tx(s.name)}</div>
                    <div className="tiny muted">{tx(s.cat)} · {tx(s.dur)} · {tx('assigned to')} {teamById(order.assigned[0])?.name}</div>
                  </div>
                  <div style={{ textAlign: 'right', flexShrink: 0, whiteSpace: 'nowrap' }}>
                    <div className="mono strong">{zl(displayed(s.net))}</div>
                    <div className="tiny muted">{tx('net')} {zl(s.net)}</div>
                  </div>
                </div>
              );
            })}
          </div>

          {/* tickets */}
          <div className="between">
            <div className="row" style={{ gap: 9 }}>
              <h3 style={{ fontSize: 15, fontWeight: 650, margin: 0 }}>{tx('Tickets')}</h3>
              <Badge kind="neutral">{tickets.length}</Badge>
              <span className="tiny muted">· {fmt('{a} approved · {b} awaiting', { a: approved.length, b: tickets.filter((t) => t.status === 'proposed').length })}</span>
            </div>
            <button className="btn btn-primary sm" onClick={() => setShowNew(true)}>
              {React.createElement(Icon.plus, { size: 15, stroke: 2.6 })} {tx('New ticket')}
            </button>
          </div>

          <div className="col" style={{ gap: 12 }}>
            {tickets.map((t) => (
              <TicketCard key={t.id} t={t}
                onApprove={approveT} onDecline={declineT} onRepropose={reproposeT}
                onAttach={attach} onSendChat={sendChat} />
            ))}
          </div>
        </div>

        {/* RIGHT — running total + payment */}
        <div className="col" style={{ gap: 18, position: 'sticky', top: 0 }}>
          <div className="card card-pad">
            <div className="between" style={{ marginBottom: 6 }}>
              <h3 style={{ fontSize: 14, fontWeight: 650, margin: 0 }}>{tx('Running total')}</h3>
              <Badge kind="accent">{tx('live')}</Badge>
            </div>
            <div className="total-row"><span>{fmt('Base work ({n})', { n: order.services.length })}</span><span className="v">{zl(baseDisp)}</span></div>
            {approved.map((t) => (
              <div className="total-row" key={t.id}>
                <span className="muted2" style={{ fontSize: 12.5 }}>+ {tx(t.title)}</span>
                <span className="v">{zl(displayed(t.net))}</span>
              </div>
            ))}
            {approved.length === 0 && <div className="total-row muted"><span>{tx('Approved tickets')}</span><span className="v">—</span></div>}
            <div className="total-grand">
              <span className="lab">{tx('Customer pays')}</span>
              <span className="v" key={bumpKey}><span className="total-bump">{zl(grand)}</span></span>
            </div>
            <div className="divider" />
            <div className="total-row muted"><span>{fmt('Shop net ({n}% take rate)', { n: Math.round(TAKE_RATE * 100) })}</span><span className="v">{zl(netTotal)}</span></div>
            <div className="total-row muted"><span>{tx('Platform commission')}</span><span className="v">{zl(commission)}</span></div>
            {tickets.some((t) => t.status === 'proposed') && (
              <div className="tiny muted" style={{ marginTop: 8, display: 'flex', gap: 6 }}>
                {React.createElement(Icon.clock, { size: 13 })} {tickets.filter((t) => t.status === 'proposed').reduce((a, t) => a + displayed(t.net), 0) > 0 ? fmt('{amt} awaiting client approval', { amt: zl(tickets.filter((t) => t.status === 'proposed').reduce((a, t) => a + displayed(t.net), 0)) }) : tx('awaiting client')}
              </div>
            )}
          </div>

          {/* payment panel */}
          <div className="card card-pad">
            <div className="between" style={{ marginBottom: 12 }}>
              <h3 style={{ fontSize: 14, fontWeight: 650, margin: 0 }}>{tx('Payment')}</h3>
              <Seg value={method} onChange={setMethod} options={[{ value: 'cash', label: tx('Cash'), icon: 'cash' }, { value: 'card', label: tx('Card'), icon: 'card' }]} />
            </div>

            {method === 'cash' ? (
              <div className="col" style={{ gap: 10 }}>
                <div className="tiny muted" style={{ lineHeight: 1.5 }}>
                  {tx('Cash on pickup. No hold is placed. Platform commission is')} <b>{tx('accrued')}</b> {tx('and billed to the shop separately.')}
                </div>
                <div className="between" style={{ padding: '8px 0' }}>
                  <span className="sec">{tx('Due on pickup')}</span>
                  <span className="mono strong" style={{ fontSize: 18 }}>{zl(grand)}</span>
                </div>
                {status === 'paid' ? (
                  <Badge kind="success" pip>{fmt('Paid in cash · {amt} collected', { amt: zl(grand) })}</Badge>
                ) : status === 'ready' ? (
                  <>
                    <div className="field" style={{ margin: 0 }}>
                      <label>{tx('Amount collected')}</label>
                      <div className="input-money"><span>zł</span>
                        <input className="input" type="number" placeholder={String(grand)} value={collected} onChange={(e) => setCollected(e.target.value)} /></div>
                    </div>
                    <button className="btn btn-success block" onClick={recordCash}>
                      {React.createElement(Icon.cash, { size: 16 })} {tx('Record cash payment')}
                    </button>
                  </>
                ) : (
                  <div className="tiny muted">{tx('Available once the order is marked')} <b>{tx('Ready')}</b>.</div>
                )}
                {status === 'paid' && <div className="tiny muted">{tx('Commission to invoice:')} <b className="mono">{zl(commission)}</b></div>}
              </div>
            ) : (
              <div className="col" style={{ gap: 10 }}>
                <div className="tiny muted" style={{ lineHeight: 1.5 }}>
                  {tx('Card via Stripe Connect. Hold on confirm, capture on completion with automatic commission split.')}
                </div>
                <div className="total-row"><span>{tx('Authorized hold')}</span><span className="v">{zl(baseDisp)}</span></div>
                <div className="total-row"><span>{tx('Re-auth (approved tickets)')}</span><span className="v">{zl(ticketsDisp)}</span></div>
                <div className="total-grand" style={{ paddingTop: 10 }}>
                  <span className="lab">{status === 'paid' ? tx('Captured') : tx('To capture')}</span><span className="v" style={{ fontSize: 19 }}>{zl(grand)}</span>
                </div>
                {status === 'paid'
                  ? <Badge kind="success" pip>{fmt('Captured · split {net} shop / {com} platform', { net: zl(netTotal), com: zl(commission) })}</Badge>
                  : status === 'ready'
                    ? <button className="btn btn-success block" onClick={capture}>{React.createElement(Icon.card, { size: 16 })} {fmt('Capture {amt}', { amt: zl(grand) })}</button>
                    : <Badge kind="accent" pip>{tx('Funds held · capture on completion')}</Badge>}
              </div>
            )}
          </div>

          {/* completion gate */}
          {status === 'in_progress' && (
            <div className="card card-pad">
              <div className="row" style={{ gap: 8, marginBottom: 10 }}>
                {React.createElement(Icon[canReady ? 'checkCircle' : 'alert'], { size: 16, style: { color: canReady ? 'var(--success)' : 'var(--warning)' } })}
                <span className="strong sec">{tx('Completion checklist')}</span>
              </div>
              <div className="col" style={{ gap: 7 }}>
                {approved.map((t) => {
                  const ok = t.type === 'order' ? (!!t.receipt && t.photos.length > 0) : t.photos.length > 0;
                  return (
                    <div className="between tiny" key={t.id}>
                      <span className="muted2">{tx(t.title)}</span>
                      {ok ? <Badge kind="success">{React.createElement(Icon.check, { size: 11, stroke: 3 })} {tx(TICKET_TYPES[t.type].req)}</Badge>
                          : <Badge kind="danger">{fmt('{req} missing', { req: tx(TICKET_TYPES[t.type].req) })}</Badge>}
                    </div>
                  );
                })}
                {approved.length === 0 && <div className="tiny muted">{tx('No approved tickets — base work photos only.')}</div>}
              </div>
              <button className="btn btn-primary block lg" style={{ marginTop: 14 }} disabled={!canReady} onClick={markReady}>
                {React.createElement(Icon.flag, { size: 16 })} {tx('Mark ready & notify customer')}
              </button>
              {!canReady && <div className="tiny" style={{ color: 'var(--danger)', marginTop: 8, textAlign: 'center' }}>{tx('Attach required photos/receipts to continue')}</div>}
            </div>
          )}

          {/* assigned */}
          <div className="card card-pad">
            <div className="between" style={{ marginBottom: 10 }}><span className="strong sec">{tx('Assigned')}</span>
              <button className="btn btn-ghost sm" onClick={() => setShowAssign(true)}>{React.createElement(Icon.plus, { size: 14 })} {tx('Assign')}</button></div>
            {order.assigned.map((id) => {
              const u = teamById(id);
              return <div className="row" key={id} style={{ gap: 10 }}><Avatar name={u.name} accent /><div><div className="sec strong">{u.name}</div><div className="tiny muted">{tx(u.role)}</div></div></div>;
            })}
          </div>
        </div>
      </div>

      {showNew && <NewTicketModal onClose={() => setShowNew(false)} onCreate={createT} />}
      {showAssign && <AssignModal assigned={order.assigned} onClose={() => setShowAssign(false)} onSave={saveAssign} />}
    </div>
  );
}

window.WorkOrderView = WorkOrderView;
