<?php
/**
 * Slice 8Z-z-A' + 8Z-z-B smoke test.
 * Runs against project 634 / contract 12.
 * NOTE: preserves the 50 seeded sites (from seed_vodacom_sites.php) — only wipes
 *       project-level POCs, blueprints, and any assets created by this test.
 */
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',
    'ServiceContractPocs.php',
    'ServiceContractAssetSpecs.php',
    'AssetTypes.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();
$pp  = new ServiceContractPocs();
$sp  = new ServiceContractAssetSpecs();

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

/* Cleanup (project-level POCs + specs + spec-linked assets only) */
$db->insertUpdate("DELETE FROM service_contract_pocs WHERE contract_id = :c", [':c' => $CID]);
$db->insertUpdate("DELETE FROM service_contract_assets WHERE contract_id = :c AND spec_id IS NOT NULL", [':c' => $CID]);
$db->insertUpdate("DELETE FROM service_contract_asset_specs WHERE contract_id = :c", [':c' => $CID]);

/* ── Project-level POCs ──────────────────────────────────────────── */
h('1. Project-level POCs');
$r1 = $pp->save($CID, ['poc_role' => 'ACCOUNT_MANAGER', 'poc_name' => 'Neema Chuwa',   'poc_phone' => '+255756000001', 'poc_email' => 'neema.chuwa@vodacom.co.tz', 'is_primary' => 1], $UID);
$r2 = $pp->save($CID, ['poc_role' => 'REGIONAL_OPS',    'poc_name' => 'Baraka Massawe','poc_phone' => '+255756000002', 'is_primary' => 0], $UID);
$r3 = $pp->save($CID, ['poc_role' => 'ESCALATION',      'poc_name' => 'Eng. Kimario',  'poc_phone' => '+255756000003', 'is_primary' => 0], $UID);
ok($r1['ok'] && $r2['ok'] && $r3['ok'], '3 project POCs saved');

$list = $pp->listFor($CID);
ok(count($list) === 3, 'listFor returns 3');
$primaries = array_filter($list, fn($p) => (int)$p['is_primary'] === 1);
ok(count($primaries) === 1, 'exactly one primary');

// Flip regional-ops to primary → old primary must demote
$pp->save($CID, ['c0d' => $r2['id'], 'poc_role' => 'REGIONAL_OPS', 'poc_name' => 'Baraka Massawe', 'is_primary' => 1], $UID);
$list2 = $pp->listFor($CID);
$primaries2 = array_filter($list2, fn($p) => (int)$p['is_primary'] === 1);
ok(count($primaries2) === 1, 'still exactly one primary after flip');
$newPrim = reset($primaries2);
ok((int)$newPrim['c0d'] === (int)$r2['id'], 'primary flipped to regional-ops');

// Soft-delete one
$pp->remove((int)$r3['id']);
ok(count($pp->listFor($CID)) === 2, 'soft-delete honoured (2 left)');

/* ── Equipment blueprints ────────────────────────────────────────── */
h('2. Equipment blueprints (specs)');
$types = (new AssetTypes())->all(true);
$typeByCode = [];
foreach ($types as $t) $typeByCode[$t['code']] = (int)$t['c0d'];
$genType = $typeByCode['GEN'] ?? 0;
$acType  = $typeByCode['AC']  ?? 0;
if (!$genType || !$acType) { echo "✗ asset_types missing GEN or AC\n"; exit(1); }

$s1 = $sp->save($CID, ['spec_code' => 'VDC-GEN-40', 'spec_name' => 'Vodacom standard 40kVA genset',
                        'asset_type_id' => $genType, 'make' => 'Cummins', 'model' => 'C40 D5',
                        'size_value' => 40, 'size_unit' => 'kVA', 'default_warranty_months' => 12], $UID);
$s2 = $sp->save($CID, ['spec_code' => 'VDC-AC-18',  'spec_name' => 'Vodacom standard 18kBTU AC',
                        'asset_type_id' => $acType,  'make' => 'Midea',   'model' => 'MSY-18',
                        'size_value' => 18, 'size_unit' => 'kBTU', 'default_warranty_months' => 12], $UID);
ok($s1['ok'] && $s2['ok'], '2 blueprints saved');

// Duplicate spec_code — must fail
$s3 = $sp->save($CID, ['spec_code' => 'VDC-GEN-40', 'spec_name' => 'dup',
                        'asset_type_id' => $genType], $UID);
ok(!$s3['ok'] && strpos($s3['msg'] ?? '', 'already exists') !== false, 'duplicate spec_code rejected');

$specs = $sp->listFor($CID);
ok(count($specs) === 2, 'listFor returns 2 (joined with asset_types)');
ok(isset($specs[0]['asset_type_name']), 'joined asset_type_name present');
ok(isset($specs[0]['units_deployed']) && (int)$specs[0]['units_deployed'] === 0, 'units_deployed = 0 pre-apply');

/* ── Bulk-apply ──────────────────────────────────────────────────── */
h('3. Bulk-apply blueprint to sites');
$siteIds = array_map(fn($s) => (int)$s['c0d'], $sc->sitesFor($CID));
if (count($siteIds) < 5) { echo "✗ need seed_vodacom_sites.php run first (found only " . count($siteIds) . " sites)\n"; exit(1); }

// Apply GEN blueprint (1 per site) to 5 Coast sites.
$firstFive = array_slice($siteIds, 0, 5);
$appliedGen = $sp->applyToSites((int)$s1['id'], $firstFive, 1, $UID);
ok($appliedGen['ok'] === true, 'GEN blueprint bulk-apply ok');
ok((int)$appliedGen['created'] === 5, "created 5 GEN units ({$appliedGen['created']})");
ok((int)$appliedGen['sites_touched'] === 5, '5 sites touched');

// Apply AC blueprint (2 per site) to same 5 sites.
$appliedAc = $sp->applyToSites((int)$s2['id'], $firstFive, 2, $UID);
ok((int)$appliedAc['created'] === 10, "created 10 AC units (2 × 5) ({$appliedAc['created']})");

// Verify units_deployed counter now reflects reality
$specs2 = $sp->listFor($CID);
$genSpec = null; foreach ($specs2 as $s) if ($s['spec_code'] === 'VDC-GEN-40') $genSpec = $s;
ok((int)$genSpec['units_deployed'] === 5, 'GEN spec units_deployed = 5');

// Cap at 20 per site
$capTest = $sp->applyToSites((int)$s1['id'], [$firstFive[0]], 21, $UID);
ok(!$capTest['ok'] && strpos($capTest['msg'] ?? '', 'capped at 20') !== false, 'qty>20 rejected');

// Cross-contract site rejection: fake site id
$badTest = $sp->applyToSites((int)$s1['id'], [999999], 1, $UID);
ok(!$badTest['ok'], 'unknown site id rejected');

/* ── Assets check post-apply ─────────────────────────────────────── */
h('4. Assets · spec_id + generated asset_no format');
$assets = $sc->assetsFor($CID);
$specLinked = array_filter($assets, fn($a) => !empty($a['spec_id']));
ok(count($specLinked) >= 15, 'at least 15 assets carry spec_id (5 GEN + 10 AC)');

// asset_no should follow SPEC-SITECODE-NN convention
$sample = null;
foreach ($assets as $a) if ((int)$a['spec_id'] === (int)$s1['id']) { $sample = $a; break; }
ok($sample !== null, 'sample GEN asset found');
if ($sample) {
    $expected = 'VDC-GEN-40-';
    ok(str_starts_with((string)$sample['asset_no'], $expected), "asset_no starts with '$expected' (got '{$sample['asset_no']}')");
    ok((int)$sample['size_value'] === 40 && $sample['size_unit'] === 'kVA', 'blueprint make/size copied to asset');
}

/* ── Soft-delete a spec — assets remain, count updates ───────────── */
h('5. Spec soft-delete');
$sp->remove((int)$s2['id']);
$specsAfter = $sp->listFor($CID);
ok(count($specsAfter) === 1, 'spec listFor returns 1 (soft-deleted excluded)');
$acCount = (int)$db->mySelect(
    "SELECT COUNT(*) n FROM service_contract_assets WHERE contract_id = :c AND spec_id = :s",
    [':c' => $CID, ':s' => (int)$s2['id']]
)[0]['n'];
ok($acCount === 10, 'assets remain in place (10 AC still linked to removed spec)');

/* Cleanup */
$db->insertUpdate("DELETE FROM service_contract_pocs WHERE contract_id = :c", [':c' => $CID]);
$db->insertUpdate("DELETE FROM service_contract_assets WHERE contract_id = :c AND spec_id IS NOT NULL", [':c' => $CID]);
$db->insertUpdate("DELETE FROM service_contract_asset_specs WHERE contract_id = :c", [':c' => $CID]);

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