<?php
/**
 * Slice 7 end-to-end verify — handoff notifications.
 *
 *   1) Fresh tender → advance to WON → confirm every FM got a TENDER_WON row
 *   2) Advance to AWARDED → confirm every Exec got a TENDER_AWARDED row
 *   3) Contract terms + chain (FM approve, Exec approve) → project auto-provisioned
 *   4) Confirm PROJECT_PROVISIONED went to CRM submitter + PM + Accountant + Procurement
 *   5) Confirm PM got STARTER_TASK_ASSIGNED roll-up ping
 *   6) PM assigns PC on ASSIGN_PC task → confirm PC got STARTER_TASK_ASSIGNED
 *   7) Read unreadCountForUser for each role, ensure > 0 as expected
 */
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'] 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();
$ps = new ProjectStarter();
$nm = new Notifications();

$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'] ?? '');

// Baseline unread counts
$before = [
    'CRM'  => $nm->unreadCountForUser($uidCrm),
    'FM'   => $nm->unreadCountForUser($uidFm),
    'EXEC' => $nm->unreadCountForUser($uidExec),
    'ACC'  => $nm->unreadCountForUser($accId),
    'PROC' => $nm->unreadCountForUser($procId),
    'PM'   => $nm->unreadCountForUser($pmId),
    'PC'   => $nm->unreadCountForUser($pcId),
];
p("Baseline unread: " . json_encode($before));

$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(), 22000000, 'TZS', 'PREP', 'OPEN', :u, :un, NOW())",
    [':tn' => 'T-E2E7-' . $stamp, ':tt' => 'SLICE 7 · handoff notifications', ':u' => $uidCrm, ':un' => $unmCrm]
);
$tid = (int)($fb['last_id'] ?? 0);
p("Tender c0d=$tid, created_by=$uidCrm");
$tm->advanceStage($tid, 'SUBMISSION', 's', $uidCrm, $unmCrm);
$tm->advanceStage($tid, 'FOLLOW_UP',  's', $uidCrm, $unmCrm);
$tm->advanceStage($tid, 'OPENING',    's', $uidCrm, $unmCrm);

/* 1 — WON → FM group */
h('1. Record WON → every FM gets TENDER_WON');
$tm->recordResult($tid, 'WON', date('Y-m-d'), '', 22000000, '', '', $uidCrm, $unmCrm);
$fmRow = $db->mySelect("SELECT COUNT(*) n FROM notifications WHERE recipient_user_id = :u AND kind = 'TENDER_WON' AND entity_id = :t", [':u' => $uidFm, ':t' => $tid]);
ok((int)$fmRow[0]['n'] === 1, "FM has 1 TENDER_WON row for this tender");

/* 2 — AWARDED → Exec group */
h('2. Advance to AWARDED → every Exec gets TENDER_AWARDED');
$tm->advanceStage($tid, 'AWARDED', 'awarded', $uidCrm, $unmCrm);
$exRow = $db->mySelect("SELECT COUNT(*) n FROM notifications WHERE recipient_user_id = :u AND kind = 'TENDER_AWARDED' AND entity_id = :t", [':u' => $uidExec, ':t' => $tid]);
ok((int)$exRow[0]['n'] === 1, "Exec has 1 TENDER_AWARDED row for this tender");

/* 3 — Contract terms + chain → project auto-provisioned */
h('3. Contract terms + FM+Exec approvals → project auto-provisioned');
$tm->saveContractTerms($tid, ['contract_value' => 22000000, 'vat_rate' => 18, 'currency' => 'TZS', 'payment_terms' => 'Net 30', 'advance_pct' => 20, 'retention_pct' => 5, 'contract_duration_days' => 60, 'expected_start_date' => date('Y-m-d')], $uidFm);
$res = $ac->submit(['chain_key' => 'TENDER_CONTRACT_APPROVAL', 'entity_type' => 'TENDER_CONTRACT', 'entity_id' => $tid, 'ref_label' => 'S7', 'return_url' => PROOT . 'Tenders/view/' . $tid, 'user_id' => $uidCrm, 'user_name' => $unmCrm, 'user_group' => $ugCrm]);
if (!$res['ok']) boom('submit failed: ' . $res['msg']);
$aid = (int)$res['approval_id'];
$ac->approve(['approval_id'=>$aid, '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'=>$aid, 'user_id'=>$uidExec, 'user_name'=>$unmExec, 'user_group'=>$ugExec, 'comment'=>'', 'assignments'=>['PROJECT_MANAGER'=>['user_id'=>$pmId,'user_name'=>$pmNm]]]);
$a = $ac->approvalById($aid);
$staged = $ac->decodePayload((string)($a['step_payload_json'] ?? ''));
$tm->onContractApproved($tid, $uidExec, $unmExec, $staged['assignments'] ?? []);
$t = $tm->find($tid); $pid = (int)$t['linked_project_id'];
p("Project auto-provisioned: c0d=$pid");

/* 4 — PROJECT_PROVISIONED fanout */
h('4. PROJECT_PROVISIONED reaches CRM submitter + PM + Accountant + Procurement');
foreach ([['CRM',$uidCrm], ['PM',$pmId], ['Accountant',$accId], ['Procurement',$procId]] as $r) {
    $n = $db->mySelect("SELECT COUNT(*) n FROM notifications WHERE recipient_user_id = :u AND kind = 'PROJECT_PROVISIONED' AND entity_id = :p", [':u' => $r[1], ':p' => $pid]);
    ok((int)$n[0]['n'] === 1, "$r[0] got PROJECT_PROVISIONED");
}

/* 5 — PM STARTER_TASK_ASSIGNED roll-up */
h('5. PM gets STARTER_TASK_ASSIGNED roll-up when checklist seeded');
$rr = $db->mySelect("SELECT COUNT(*) n FROM notifications WHERE recipient_user_id = :u AND kind = 'STARTER_TASK_ASSIGNED' AND entity_id = :p", [':u' => $pmId, ':p' => $pid]);
ok((int)$rr[0]['n'] >= 1, "PM got STARTER_TASK_ASSIGNED roll-up");

/* 6 — PM assigns PC → PC gets STARTER_TASK_ASSIGNED */
h('6. PM assigns PC on ASSIGN_PC → PC gets STARTER_TASK_ASSIGNED');
$tasks = $ps->tasksFor($pid);
$assignPc = null; foreach ($tasks as $tt) if ($tt['task_key'] === 'ASSIGN_PC') $assignPc = $tt;
if (!$assignPc) boom('ASSIGN_PC task not found');
$ps->assignOwner((int)$assignPc['c0d'], $pcId, $pcNm, $pmId);
$pcNotif = $db->mySelect("SELECT COUNT(*) n FROM notifications WHERE recipient_user_id = :u AND kind = 'STARTER_TASK_ASSIGNED' AND entity_type = 'project_starter_tasks' AND entity_id = :t", [':u' => $pcId, ':t' => (int)$assignPc['c0d']]);
ok((int)$pcNotif[0]['n'] === 1, "PC got STARTER_TASK_ASSIGNED for the assign-PC task");

/* 7 — Delta unread counts */
h('7. Unread deltas per role');
$after = [
    'CRM'  => $nm->unreadCountForUser($uidCrm),
    'FM'   => $nm->unreadCountForUser($uidFm),
    'EXEC' => $nm->unreadCountForUser($uidExec),
    'ACC'  => $nm->unreadCountForUser($accId),
    'PROC' => $nm->unreadCountForUser($procId),
    'PM'   => $nm->unreadCountForUser($pmId),
    'PC'   => $nm->unreadCountForUser($pcId),
];
foreach ($after as $r => $n) p(sprintf("  %-5s before=%-3d after=%-3d delta=%+d", $r, $before[$r], $n, $n - $before[$r]));
ok($after['FM']   > $before['FM'],   'FM unread went up (WON ping)');
ok($after['EXEC'] > $before['EXEC'], 'EXEC unread went up (AWARDED ping)');
ok($after['CRM']  > $before['CRM'],  'CRM unread went up (project provisioned)');
ok($after['PM']   > $before['PM'],   'PM unread went up (checklist)');
ok($after['PC']   > $before['PC'],   'PC unread went up (assignment)');

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