<?php $e=static fn($v)=>htmlspecialchars((string)$v,ENT_QUOTES,'UTF-8'); $invoice=$invoice??null; $form=$form??[]; $items=$invoice['items']??[]; if(!$items)$items=[['service_id'=>'','description'=>'','service_date'=>'','quantity'=>'1','unit_price'=>'']]; $value=static fn($k,$d='')=>$form[$k]??($invoice[$k]??$d); ?>
<section class="page-header"><div><p class="eyebrow">Billing · Invoice</p><h1><?= $invoice?$e($invoice['invoice_number']):'New Invoice' ?></h1><p><?= $e($pageDescription??'') ?></p></div><a class="btn btn-secondary" href="/crm/public/invoices">Back to Invoices</a></section>
<?php if(!empty($error)): ?><div class="alert alert-error"><?= $e($error) ?></div><?php endif; ?><?php if(!empty($message)): ?><div class="alert alert-success"><?= $e($message) ?></div><?php endif; ?>
<section class="card"><div class="card-header"><div><h2>Invoice details</h2><p>Invoice totals are calculated on the server from the line items.</p></div><?php if($invoice): ?><span class="badge badge-muted"><?= $e(ucfirst($invoice['status'])) ?></span><?php endif; ?></div>
<form method="post" action="<?= $invoice?'/crm/public/invoices/'.(int)$invoice['id'].'/edit':'/crm/public/invoices/create' ?>" id="invoice-form" class="form-stack"><input type="hidden" name="_csrf" value="<?= $e($csrf) ?>"><div class="grid grid-2"><label class="form-field"><span>Patient</span><select name="patient_id" required><option value="">Select patient</option><?php foreach($patients as $p): ?><option value="<?= (int)$p['id'] ?>" <?= (string)$value('patient_id')===(string)$p['id']?'selected':'' ?>><?= $e($p['first_name'].' '.$p['last_name'].' — '.$p['patient_reference']) ?></option><?php endforeach; ?></select></label><label class="form-field"><span>Invoice date</span><input type="date" name="invoice_date" required value="<?= $e($value('invoice_date',date('Y-m-d'))) ?>"></label><label class="form-field"><span>Due date</span><input type="date" name="due_date" value="<?= $e($value('due_date')) ?>"></label><label class="form-field"><span>Discount (KSh)</span><input type="text" inputmode="decimal" name="discount" value="<?= $e($value('discount','0')) ?>"></label><label class="form-field"><span>Tax (KSh)</span><input type="text" inputmode="decimal" name="tax" value="<?= $e($value('tax','0')) ?>"></label></div></section>
<section class="card"><div class="card-header"><div><h2>Invoice items</h2><p>Select a service or enter a custom description.</p></div><div class="invoice-item-actions"><strong data-invoice-live-total>KSh 0.00</strong><button class="btn btn-secondary" type="button" id="add-item">+ Add item</button></div></div><div class="table-wrap"><table class="data-table" id="invoice-items"><thead><tr><th>Service</th><th>Description</th><th>Service date</th><th>Amount</th><th></th></tr></thead><tbody><?php foreach($items as $idx=>$item): ?><tr><td><select name="items[<?= (int)$idx ?>][service_id]" data-item-field="service_id" class="service-select"><option value="">Custom</option><?php foreach($services as $s): ?><option value="<?= (int)$s['id'] ?>" data-price="<?= $e($s['price']) ?>" data-name="<?= $e($s['name']) ?>" <?= (string)($item['service_id']??'')===(string)$s['id']?'selected':'' ?>><?= $e($s['name']) ?> — KSh <?= number_format((float)$s['price'],2) ?></option><?php endforeach; ?></select></td><td><input type="text" name="items[<?= (int)$idx ?>][description]" data-item-field="description" required value="<?= $e($item['description']??'') ?>"></td><td><input type="date" name="items[<?= (int)$idx ?>][service_date]" data-item-field="service_date" value="<?= $e($item['service_date']??'') ?>"></td><td><input type="text" inputmode="decimal" name="items[<?= (int)$idx ?>][unit_price]" data-item-field="unit_price" required value="<?= $e($item['unit_price']??'0') ?>"><input type="hidden" name="items[<?= (int)$idx ?>][quantity]" data-item-field="quantity" value="1"></td><td><button type="button" class="btn btn-small btn-secondary remove-item">Remove</button></td></tr><?php endforeach; ?></tbody></table></div><div class="invoice-live-summary"><div><span>Live total</span><strong id="invoice-live-total">KSh 0.00</strong></div></div><div class="form-field"><span>Notes</span><textarea name="notes" rows="4"><?= $e($value('notes')) ?></textarea></div><div class="form-actions"><?php if($invoice && \App\Core\Auth::hasPermission('invoice.view')): ?><a class="btn btn-secondary" href="/crm/public/invoices/<?= (int)$invoice['id'] ?>/pdf" target="_blank">View / Print PDF</a><?php endif; ?><?php if($invoice && \App\Core\Auth::hasPermission('invoice.create')): ?><button class="btn btn-secondary" type="submit" form="email-invoice-form">Email Invoice PDF</button><?php endif; ?><a class="btn btn-secondary" href="/crm/public/invoices">Cancel</a><button class="btn btn-primary" type="submit"><?= $invoice?'Save Invoice':'Create Invoice' ?></button></div></form><?php if($invoice && \App\Core\Auth::hasPermission('invoice.create')): ?><form id="email-invoice-form" method="post" action="/crm/public/invoices/<?= (int)$invoice['id'] ?>/email"><input type="hidden" name="_csrf" value="<?= $e($csrf) ?>"></form><?php endif; ?></section>
<?php if($invoice): ?><section class="card"><div class="card-header"><div><h2>Invoice actions</h2><p>Payments and paid/partial status are now available.</p></div></div><div class="form-actions"><?php if($invoice['status']!=='cancelled' && \App\Core\Auth::hasPermission('payment.create')): ?><a class="btn btn-primary" href="/crm/public/invoices/<?= (int)$invoice['id'] ?>/payment">Record Payment</a><?php endif; ?><?php if($invoice['status']!=='cancelled'): ?><form method="post" action="/crm/public/invoices/<?= (int)$invoice['id'] ?>/status"><input type="hidden" name="_csrf" value="<?= $e($csrf) ?>"><input type="hidden" name="status" value="cancelled"><button class="btn btn-secondary" type="submit">Cancel Invoice</button></form><?php endif; ?></div></section><?php endif; ?>
<script>
(function () {
  'use strict';
  const tbody=document.querySelector('#invoice-items tbody');
  const add=document.getElementById('add-item');
  const total=document.getElementById('invoice-live-total');
  if(!tbody||!add)return;
  const money=v=>{const n=parseFloat(String(v??'').replace(/,/g,'').trim());return Number.isFinite(n)?n:0;};
  const fmt=n=>n.toLocaleString('en-KE',{minimumFractionDigits:2,maximumFractionDigits:2});
  const rows=()=>Array.from(tbody.querySelectorAll('tr'));
  function renumber(){
    rows().forEach((row,i)=>{
      row.querySelectorAll('[data-item-field]').forEach(el=>{
        el.name='items['+i+']['+el.dataset.itemField+']';
      });
    });
  }
  function recalc(){
    let sum=0;
    rows().forEach(row=>{
      sum+=money(row.querySelector('[data-item-field="quantity"]')?.value||1)*
            money(row.querySelector('[data-item-field="unit_price"]')?.value);
    });
    if(total)total.textContent='KSh '+fmt(sum);
  }
  function clearRow(row){
    row.querySelectorAll('input[data-item-field]').forEach(i=>{
      i.value=i.dataset.itemField==='quantity'?'1':'';
    });
    const sel=row.querySelector('select[data-item-field="service_id"]');
    if(sel)sel.selectedIndex=0;
  }
  add.type='button';
  add.addEventListener('click',e=>{
    e.preventDefault();
    const first=rows()[0]; if(!first)return;
    const row=first.cloneNode(true); clearRow(row); tbody.appendChild(row);
    renumber(); recalc();
    row.querySelector('[data-item-field="description"]')?.focus();
  });
  tbody.addEventListener('click',e=>{
    const btn=e.target.closest('.remove-item'); if(!btn)return;
    e.preventDefault();
    const row=btn.closest('tr');
    if(rows().length>1)row.remove();else clearRow(row);
    renumber();recalc();
  });
  tbody.addEventListener('change',e=>{
    const sel=e.target.closest('.service-select'); if(!sel)return;
    const row=sel.closest('tr'),o=sel.options[sel.selectedIndex];
    if(o&&o.value){
      const d=row.querySelector('[data-item-field="description"]');
      const p=row.querySelector('[data-item-field="unit_price"]');
      if(d)d.value=o.dataset.name||o.textContent.trim();
      if(p)p.value=o.dataset.price||'';
    }
    recalc();
  });
  tbody.addEventListener('input',e=>{
    if(e.target.matches('[data-item-field="quantity"],[data-item-field="unit_price"]'))recalc();
  });
  const form=add.closest('form');
  if(form)form.addEventListener('submit',()=>{renumber();recalc();});
  renumber();recalc();
})();
</script>
