<?php
/**
 * Slice 8a-2 · Draft supplier LPO batch from awarded RFQ quotes.
 *
 *   1) Drive tender → project pipeline · scrub PO · ensure RFQ.
 *   2) Invite 2 vendors, capture quotes for each PO line, award some to each.
 *   3) Preview: expect exactly 2 vendor groups.
 *   4) draftBatchForProject → 2 SUPPLIER LPOs materialised (one per vendor).
 *   5) Verify lpos rows have correct amount + item counts + sourced_from_rfq_id.
 *   6) Re-run drafter → both groups now "already drafted", 0 new LPOs.
 *   7) PC completes DRAFT_LPO_BATCH starter task via ProjectStarter.
 */
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__DIR__));
require_once ROOT . DS . 'config' . DS . 'config.php';
require_once ROOT . DS . 'core' . DS . 'Application.php';
require_once ROOT . DS . 'core' . DS . 'Model.php';
require_once ROOT . DS . 'core' . DS . 'DB.php';
$_SESSION = $_SESSION ?? [];
foreach ([
    'ApprovalChain.php','Tenders.php','TenderPricing.php','ProjectStarter.php',
    'Notifications.php','GoodsClientPos.php','GoodsScrub.php','GoodsRfq.php','Lpos.php',
] as $m) require_once ROOT . DS . 'app' . DS . 'models' . DS . $m;

function h(string $t): void { echo "\n==== $t ====\n"; }
function p(string $t): void { echo "  $t\n"; }
function ok(bool $c, string $m): void { echo ($c ? "  ✓ " : "  ✗ ") . $m . "\n"; }
function boom(string $why) { echo "\nFATAL: $why\n"; exit(1); }

$db = new DB();
$ac = new ApprovalChain();
$tm = new Tenders();
$pm = new TenderPricing();
$ps = new ProjectStarter();
$gs = new GoodsScrub();
$rq = new GoodsRfq();
$lp = new Lpos();

$uidCrm = 100; $unmCrm = 'CRM Test User';       $ugCrm  = 'CRM';
$uidFm  = 3;   $unmFm  = 'Finance Manager Test'; $ugFm  = 'Finance Manager';
$uidExec= 2;   $unmExec= 'Executive Test';      $ugExec = 'Executive';
$accId  = 4;   $accNm  = 'Accountant Test';
$procId = 8;   $procNm = 'Procurement Test';
$pmId   = 5;   $pmNm   = 'Project Manager Test';
$pcRow  = $db->mySelect("SELECT c0d, full_name FROM users WHERE user_group_name='Projects Coordinator' AND status='ACTIVE' AND deleted=0 ORDER BY c0d LIMIT 1", []);
$pcId   = (int)($pcRow[0]['c0d'] ?? 0);
$pcNm   = (string)($pcRow[0]['full_name'] ?? '');

$vRow = $db->mySelect("SELECT c0d, vendor_name FROM vendors WHERE deleted = 0 ORDER BY c0d LIMIT 2", []);
if (count($vRow) < 2) boom('Need at least 2 vendors in the DB');
$v1Id = (int)$vRow[0]['c0d']; $v1Nm = (string)$vRow[0]['vendor_name'];
$v2Id = (int)$vRow[1]['c0d']; $v2Nm = (string)$vRow[1]['vendor_name'];

/* 1 — Full pipeline to a scrubbed CONFIRMED client PO with 2 items */
h('1. Pipeline: tender → project → scrub → RFQ');
$stamp = date('YmdHis');
$fb = $db->insertUpdate(
    "INSERT INTO tender_tracker
        (tender_no, tender_title, source_type, buyer_name, project_type,
         date_received, estimated_value, currency, tender_stage, tender_status,
         created_by, created_by_name, created_on)
     VALUES (:tn, :tt, 'PRIVATE_CLIENT', 'ACME Ltd.', 'goods',
         CURDATE(), 30000000, 'TZS', 'PREP', 'OPEN', :u, :un, NOW())",
    [':tn' => 'T-E2E8a2-' . $stamp, ':tt' => 'SLICE 8a-2 draft LPO', ':u' => $uidCrm, ':un' => $unmCrm]
);
$tid = (int)($fb['last_id'] ?? 0);
foreach (['SUBMISSION','FOLLOW_UP','OPENING'] as $s) $tm->advanceStage($tid, $s, 'x', $uidCrm, $unmCrm);
$vid = $pm->createVersion($tid, null, $uidCrm, $unmCrm);
$s1  = $pm->addSection($vid, $tid, 'Widgets', 'set', $uidCrm);
$pm->addLine($s1, ['item_ref'=>'A','description'=>'Widget A','qty'=>10,'uom'=>'ea','unit_cost'=>200000,'markup_pct'=>25], $uidCrm);
$pm->addLine($s1, ['item_ref'=>'B','description'=>'Widget B','qty'=>5,'uom'=>'ea','unit_cost'=>400000,'markup_pct'=>30], $uidCrm);
$res = $pm->submitForApproval($vid, $uidCrm, $unmCrm, $ugCrm);
$aidP = (int)$res['approval_id'];
$ac->approve(['approval_id'=>$aidP,'user_id'=>$pmId,'user_name'=>$pmNm,'user_group'=>'Project Manager','comment'=>'ok']);
$ac->approve(['approval_id'=>$aidP,'user_id'=>$uidFm,'user_name'=>$unmFm,'user_group'=>$ugFm,'comment'=>'ok']);
$ac->approve(['approval_id'=>$aidP,'user_id'=>$uidExec,'user_name'=>$unmExec,'user_group'=>$ugExec,'comment'=>'ok']);
$pm->onPricingDecision($vid, 'APPROVED'); $pm->applyToTender($vid);
$tm->recordResult($tid, 'WON', date('Y-m-d'), '', 30000000, '', '', $uidCrm, $unmCrm);
$tm->advanceStage($tid, 'AWARDED', 'a', $uidCrm, $unmCrm);
$tm->saveContractTerms($tid, ['contract_value' => $pm->findVersion($vid)['sum_price']], $uidFm, $ugFm, $unmFm);
$rC = $ac->submit(['chain_key'=>'TENDER_CONTRACT_APPROVAL','entity_type'=>'TENDER_CONTRACT','entity_id'=>$tid,'ref_label'=>'x','return_url'=>PROOT.'Tenders/view/'.$tid,'user_id'=>$uidCrm,'user_name'=>$unmCrm,'user_group'=>$ugCrm]);
$aidC = (int)$rC['approval_id'];
$ac->approve(['approval_id'=>$aidC,'user_id'=>$uidFm,'user_name'=>$unmFm,'user_group'=>$ugFm,'comment'=>'','assignments'=>['ACCOUNTANT'=>['user_id'=>$accId,'user_name'=>$accNm],'PROCUREMENT'=>['user_id'=>$procId,'user_name'=>$procNm]]]);
$ac->approve(['approval_id'=>$aidC,'user_id'=>$uidExec,'user_name'=>$unmExec,'user_group'=>$ugExec,'comment'=>'','assignments'=>['PROJECT_MANAGER'=>['user_id'=>$pmId,'user_name'=>$pmNm]]]);
$aC = $ac->approvalById($aidC);
$tm->onContractApproved($tid, $uidExec, $unmExec, ($ac->decodePayload((string)($aC['step_payload_json'] ?? '')))['assignments'] ?? []);
$t = $tm->find($tid); $pid = (int)$t['linked_project_id'];
$pm->snapshotToProject($tid, $pid, $uidExec, $unmExec);
// Scrub the PO so it's CONFIRMED
$po = $db->mySelect("SELECT c0d FROM goods_client_pos WHERE project_id=:p AND deleted=0 LIMIT 1", [':p'=>$pid])[0];
$gs->markScrubbed((int)$po['c0d'], $pcId, $pcNm);
// Ensure RFQ
$rfq = $rq->ensureForClientPo((int)$po['c0d'], $pcId, $pcNm);
$rfqId = (int)$rfq['id'];
p("Project $pid · client PO {$po['c0d']} · RFQ $rfqId");
ok($pid > 0 && $rfqId > 0, 'Pipeline complete to RFQ');

/* 2 — Invite 2 vendors, capture quotes, award — v1 gets item A, v2 gets item B */
h('2. Invite 2 vendors + quotes + awards');
$q1 = $rq->inviteSupplier($rfqId, $v1Id, $procId);
$q2 = $rq->inviteSupplier($rfqId, $v2Id, $procId);
$q1id = (int)$q1['id']; $q2id = (int)$q2['id'];
$items = $db->mySelect("SELECT c0d, item_no, qty FROM goods_client_po_items WHERE client_po_id = :p ORDER BY item_no", [':p' => (int)$po['c0d']]);
$itemA = $items[0]; $itemB = $items[1];
// Vendor 1 quotes both items
$rq->saveQuoteItem($q1id, (int)$itemA['c0d'], 220000, (float)$itemA['qty'], 7);
$rq->saveQuoteItem($q1id, (int)$itemB['c0d'], 430000, (float)$itemB['qty'], 10);
// Vendor 2 quotes both items
$rq->saveQuoteItem($q2id, (int)$itemA['c0d'], 250000, (float)$itemA['qty'], 5);
$rq->saveQuoteItem($q2id, (int)$itemB['c0d'], 410000, (float)$itemB['qty'], 8);
// Award item A to Vendor 1 (cheaper); item B to Vendor 2 (cheaper)
$aRow = $db->mySelect("SELECT c0d FROM goods_rfq_quote_items WHERE rfq_quote_id = :q AND client_po_item_id = :i", [':q'=>$q1id, ':i'=>(int)$itemA['c0d']])[0];
$bRow = $db->mySelect("SELECT c0d FROM goods_rfq_quote_items WHERE rfq_quote_id = :q AND client_po_item_id = :i", [':q'=>$q2id, ':i'=>(int)$itemB['c0d']])[0];
$rq->awardItem((int)$aRow['c0d'], $procId);
$rq->awardItem((int)$bRow['c0d'], $procId);
p("Awarded: item A → $v1Nm · item B → $v2Nm");
ok(true, 'Quotes captured and awarded');

/* 3 — Preview */
h('3. Preview vendor groups');
$preview = $lp->draftPreviewForProject($pid);
p("Groups: " . count($preview));
foreach ($preview as $g) p("  · {$g['vendor_name']} (rfq {$g['rfq_id']}) · " . count($g['lines']) . " line(s) · total " . number_format($g['total']));
ok(count($preview) === 2, '2 vendor groups');
foreach ($preview as $g) if ($g['already_lpo_id'] !== 0) ok(false, "Group already drafted unexpectedly");
ok(true, 'No prior draft (already_lpo_id all zero)');

/* 4 — Draft the batch */
h('4. draftBatchForProject → 2 supplier LPOs');
$res = $lp->draftBatchForProject($pid, $procId, $procNm);
$created = 0; $skipped = 0;
foreach ($res as $r) { if (!empty($r['skipped'])) $skipped++; elseif (!empty($r['ok'])) $created++; }
p("created=$created skipped=$skipped");
foreach ($res as $r) p("  · " . ($r['vendor_name'] ?? '?') . " → " . ($r['lpo_no'] ?? '?') . " (id " . ($r['lpo_id'] ?? '?') . ")" . (!empty($r['skipped']) ? ' [skipped]' : ''));
ok($created === 2 && $skipped === 0, '2 draft LPOs created, 0 skipped');

/* 5 — Verify materialised rows */
h('5. Materialised lpos + lpo_items');
$lpos = $db->mySelect("SELECT c0d, lpo_no, payee_name, amount, cash_out_status, sourced_from_rfq_id, sourced_from_client_po_id FROM lpos WHERE project_id = :p AND lpo_type = 'SUPPLIER' ORDER BY c0d", [':p' => $pid]);
ok(count($lpos) === 2, count($lpos) . ' SUPPLIER LPOs on project');
foreach ($lpos as $l) {
    $items = $db->mySelect("SELECT COUNT(*) n, SUM(line_total) s FROM lpo_items WHERE lpo_id = :l", [':l' => (int)$l['c0d']]);
    $n = (int)$items[0]['n']; $s = (float)$items[0]['s'];
    p(sprintf("  · %s · %s · %s · status=%s · sourced from RFQ %d · %d line(s) sum=%s (header amount=%s)",
        $l['lpo_no'], $l['payee_name'], number_format((float)$l['amount']), $l['cash_out_status'],
        (int)$l['sourced_from_rfq_id'], $n, number_format($s), number_format((float)$l['amount'])));
    ok($n === 1, "  {$l['lpo_no']} has 1 line (one item awarded per vendor)");
    ok(abs($s - (float)$l['amount']) < 0.01, "  {$l['lpo_no']} header amount matches line total");
    ok((int)$l['sourced_from_rfq_id'] === $rfqId, "  {$l['lpo_no']} sourced_from_rfq_id = $rfqId");
    ok($l['cash_out_status'] === 'DRAFT', "  {$l['lpo_no']} status DRAFT");
}

/* 6 — Re-run drafter: idempotent */
h('6. Re-run drafter → both groups skipped');
$res2 = $lp->draftBatchForProject($pid, $procId, $procNm);
$c2 = 0; $s2 = 0; foreach ($res2 as $r) { if (!empty($r['skipped'])) $s2++; elseif (!empty($r['ok'])) $c2++; }
p("created=$c2 skipped=$s2");
ok($c2 === 0 && $s2 === 2, 'Second run: 0 created, 2 skipped');

/* 7 — Mark DRAFT_LPO_BATCH checklist task DONE */
h('7. ProjectStarter DRAFT_LPO_BATCH → done');
$tasks = $ps->tasksFor($pid);
$tsk = null; foreach ($tasks as $tt) if ($tt['task_key'] === 'DRAFT_LPO_BATCH') $tsk = $tt;
if (!$tsk) boom('DRAFT_LPO_BATCH task missing');
$ps->assignOwner((int)$tsk['c0d'], $procId, $procNm, $pmId);
$ps->complete((int)$tsk['c0d'], $procId, $procNm, 'Draft LPOs created via /Lpos/draft');
$after = $ps->tasksFor($pid);
$done = null; foreach ($after as $tt) if ($tt['task_key'] === 'DRAFT_LPO_BATCH') $done = $tt;
ok($done && $done['status'] === 'DONE', 'DRAFT_LPO_BATCH task is DONE');

echo "\n=== END ===\n";
