<?php
/**
 * Slice 8Z-z-A · Sites & POCs register smoke test.
 * Runs against project 634 / contract 12.
 */
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';
foreach (['ServiceContracts.php','ServiceContractSitePocs.php'] as $m) {
    require_once ROOT . DS . 'app' . DS . 'models' . DS . $m;
}

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

$db  = new DB();
$sc  = new ServiceContracts();
$pm  = new ServiceContractSitePocs();

$cid = 12;
$c   = $sc->find($cid);
if (empty($c)) { echo "✗ service_contract 12 not found\n"; exit(1); }

/* Cleanup — only remove sites this test creates. Uses distinctive site_codes so
   we never nuke seeded / real data on contract 12. */
$SMOKE_CODES = ['SMOKE-CST-001', 'SMOKE-DSM-042'];
$inPh = implode(',', array_fill(0, count($SMOKE_CODES), '?'));
$smokeSids = $db->mySelect("SELECT c0d FROM service_contract_sites WHERE contract_id = ? AND site_code IN ($inPh)", array_merge([$cid], $SMOKE_CODES));
if (!empty($smokeSids)) {
    $smokeIdList = array_map(fn($r) => (int)$r['c0d'], $smokeSids);
    $inSids = implode(',', array_fill(0, count($smokeIdList), '?'));
    $db->insertUpdate("DELETE FROM service_contract_site_pocs WHERE site_id IN ($inSids)", $smokeIdList);
    $db->insertUpdate("DELETE FROM service_contract_assets WHERE site_id IN ($inSids)", $smokeIdList);
    $db->insertUpdate("DELETE FROM service_contract_sites WHERE c0d IN ($inSids)", $smokeIdList);
}

/* ── Z-A · Sites CRUD ────────────────────────────────────────── */
h('1. Sites CRUD');
$sid1 = (int)$sc->saveSite([
    'contract_id' => $cid, 'site_code' => 'SMOKE-CST-001', 'name' => 'SMOKE · Coast-001 Bagamoyo',
    'region' => 'Coast', 'district' => 'Bagamoyo', 'physical_address' => 'Plot 42, Kaole Rd',
    'gps_lat' => '-6.4419', 'gps_lng' => '38.8901',
    'is_active' => 1,
]);
ok($sid1 > 0, "SMOKE-CST-001 saved · id={$sid1}");

$sid2 = (int)$sc->saveSite([
    'contract_id' => $cid, 'site_code' => 'SMOKE-DSM-042', 'name' => 'SMOKE · Dar-042 Kinondoni',
    'region' => 'Dar', 'district' => 'Kinondoni', 'is_active' => 1,
]);
ok($sid2 > 0, "SMOKE-DSM-042 saved · id={$sid2}");

/* Only assert on the two SMOKE-* rows this test owns (contract 12 may have seeded sites). */
$allSites = $sc->sitesFor($cid);
$smokeSites = array_filter($allSites, fn($s) => in_array((string)$s['site_code'], ['SMOKE-CST-001','SMOKE-DSM-042'], true));
ok(count($smokeSites) === 2, "sitesFor includes the 2 smoke rows (total=" . count($allSites) . ")");

/* ── Z-A · POCs multi-role + primary enforcement ─────────────── */
h('2. POCs · multi-role + primary flip');
$p1 = $pm->save($sid1, ['poc_role' => 'SITE_MANAGER', 'poc_name' => 'John Mwanza', 'poc_phone' => '+255712345678', 'is_primary' => 1], 999);
ok($p1['ok'] === true && ($p1['id'] ?? 0) > 0, 'primary site-manager POC saved');

$p2 = $pm->save($sid1, ['poc_role' => 'TECH',     'poc_name' => 'Halima Said',   'poc_phone' => '+255713000000', 'is_primary' => 0], 999);
$p3 = $pm->save($sid1, ['poc_role' => 'SECURITY', 'poc_name' => 'Amos Kileo',    'poc_phone' => '+255714000000'], 999);
ok($p2['ok'] === true && $p3['ok'] === true, 'tech + security POCs saved');

$pocs = $pm->listFor($sid1);
ok(count($pocs) === 3, '3 POCs on file for Coast-001');
$primaries = array_filter($pocs, fn($p) => (int)$p['is_primary'] === 1);
ok(count($primaries) === 1, 'exactly one primary POC');
$prim = reset($primaries);
ok((string)$prim['poc_role'] === 'SITE_MANAGER', 'primary is the site manager');

// Flip TECH to primary — SITE_MANAGER must demote.
$pm->save($sid1, ['c0d' => $p2['id'], 'poc_role' => 'TECH', 'poc_name' => 'Halima Said', 'poc_phone' => '+255713000000', 'is_primary' => 1], 999);
$pocs2 = $pm->listFor($sid1);
$prims2 = array_filter($pocs2, fn($p) => (int)$p['is_primary'] === 1);
ok(count($prims2) === 1, 'still exactly one primary after flip');
$newPrim = reset($prims2);
ok((int)$newPrim['c0d'] === (int)$p2['id'], 'primary flipped to TECH row');

/* ── Z-A · Confirmation stamp ────────────────────────────────── */
h('3. POC confirmation stamp');
$conf = $pm->confirmSite($sid1, 999);
ok($conf['ok'] === true, 'confirmSite ok');
$s1 = $db->mySelect("SELECT poc_confirmed_by, poc_confirmed_on FROM service_contract_sites WHERE c0d = :s", [':s' => $sid1]);
ok(!empty($s1[0]['poc_confirmed_on']), 'poc_confirmed_on stamped');
ok((int)$s1[0]['poc_confirmed_by'] === 999, 'poc_confirmed_by = 999');

$un = $pm->unconfirmSite($sid1);
ok($un['ok'] === true, 'unconfirmSite ok');
$s2 = $db->mySelect("SELECT poc_confirmed_by, poc_confirmed_on FROM service_contract_sites WHERE c0d = :s", [':s' => $sid1]);
ok(empty($s2[0]['poc_confirmed_on']), 'confirmation cleared');

/* ── Z-A · POC remove + refresh via listForContract ──────────── */
h('4. Contract-wide POC list + soft-delete');
$rm = $pm->remove((int)$p3['id']);
ok($rm['ok'] === true, 'security POC removed');
// Filter to only this test's sites — contract 12 may hold seeded / real POCs too.
$all = $pm->listForContract($cid);
$mySids = [$sid1, $sid2];
$mine = array_filter($all, fn($p) => in_array((int)$p['site_id'], $mySids, true));
ok(count($mine) === 2, 'test-owned POC count = 2 (soft-deleted excluded)');

/* Cleanup — only touch the SMOKE-* rows this test created. */
$smokeSidsEnd = $db->mySelect("SELECT c0d FROM service_contract_sites WHERE contract_id = ? AND site_code IN ($inPh)", array_merge([$cid], $SMOKE_CODES));
if (!empty($smokeSidsEnd)) {
    $endList = array_map(fn($r) => (int)$r['c0d'], $smokeSidsEnd);
    $inEnd = implode(',', array_fill(0, count($endList), '?'));
    $db->insertUpdate("DELETE FROM service_contract_site_pocs WHERE site_id IN ($inEnd)", $endList);
    $db->insertUpdate("DELETE FROM service_contract_assets      WHERE site_id IN ($inEnd)", $endList);
    $db->insertUpdate("DELETE FROM service_contract_sites       WHERE c0d IN ($inEnd)",     $endList);
}

echo "\n=== DONE (state restored) ===\n";
