<?php
/**
 * Slice 8S-10 smoke test — round-trip of the tender_service_spec CRUD + convert mapping.
 *
 * Assumes seed_demo_services_tender.php has been run first (Vodacom sample = tender 400).
 * Does NOT mutate any live data; only reads back the persisted spec and dry-runs
 * the toContractPayload() mapper.
 */
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 (['Tenders.php','TenderServiceSpec.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();
$tss = new TenderServiceSpec();

/* Find the Vodacom PM sample tender */
$row = $db->mySelect("SELECT c0d, project_type, buyer_name, customer_id FROM tender_tracker WHERE tender_title LIKE 'DEMO-SVC · Vodacom%'", []);
if (empty($row)) { echo "✗ Vodacom sample tender not found — run seed_demo_services_tender.php first.\n"; exit(1); }
$tenderId    = (int)$row[0]['c0d'];
$projectType = (string)$row[0]['project_type'];
$customerId  = (int)$row[0]['customer_id'];
$buyerName   = (string)$row[0]['buyer_name'];

h("0. Sample tender · id=$tenderId · type=$projectType");
ok($projectType === 'services', 'project_type is services');

/* ── 1. Read back the spec ─────────────────────────────────────────── */
h('1. Read back tender_service_spec');
$spec = $tss->forTender($tenderId);
ok(!empty($spec),                                              'spec row exists');
ok((int)$spec['no_of_sites'] === 50,                           'no_of_sites = 50');
ok($spec['pm_cadence'] === 'QUARTERLY',                        'pm_cadence = QUARTERLY');
ok($spec['pm_payment_structure'] === 'MONTHLY_RETAINER',       'pm_payment_structure = MONTHLY_RETAINER');
ok((int)$spec['has_callouts'] === 1,                           'has_callouts = 1');
ok($spec['callout_payment_structure'] === 'FREE_QUOTA_PLUS_FEE','callout_payment_structure = FREE_QUOTA_PLUS_FEE');
ok((float)$spec['emergency_multiplier'] === 2.00,              'emergency_multiplier = 2.00');
ok((int)$spec['free_callouts_per_month'] === 12,               'free_callouts_per_month = 12');
ok((int)$spec['sla_emergency_hrs'] === 2,                      'sla_emergency_hrs = 2');
ok($spec['spare_policy'] === 'CLIENT',                         'spare_policy = CLIENT');
ok($spec['invoicing_cadence'] === 'MONTHLY_RETAINER',          'invoicing_cadence = MONTHLY_RETAINER');
ok((int)$spec['payment_terms_days'] === 45,                    'payment_terms_days = 45');
ok((float)$spec['labour_rate_per_hr'] === 85000.0,             'labour_rate_per_hr = 85,000');

/* ── 2. Equipment JSON decode ──────────────────────────────────────── */
h('2. Equipment JSON round-trip');
$eq = $tss->decodedEquipment($spec);
ok(count($eq) === 4,                                           '4 equipment rows');
ok($eq[0]['type'] === 'GEN',                                   'row 0 type = GEN');
ok($eq[1]['size'] === '60-100 kVA',                            'row 1 size = 60-100 kVA');
ok((int)$eq[2]['count'] === 100,                               'row 2 count = 100');

/* ── 3. toContractPayload() mapper ─────────────────────────────────── */
h('3. toContractPayload dry-run');
$payload = $tss->toContractPayload($tenderId, /* fake_project_id */ 9999, $customerId, $buyerName);
ok(!empty($payload),                                           'payload built');
ok((int)$payload['project_id'] === 9999,                       'project_id passed through');
ok($payload['currency'] === 'TZS',                             'currency = TZS (default)');
ok($payload['spare_policy'] === 'CLIENT',                      'spare_policy carried across');
ok($payload['invoice_cadence'] === 'MONTHLY_RETAINER',         'invoice_cadence carried across');
ok((int)$payload['payment_terms_days'] === 45,                 'payment_terms_days carried across');
ok((float)$payload['callout_fee'] === 350000.0,                'callout_fee carried across');
ok((float)$payload['emergency_multiplier'] === 2.00,           'emergency_multiplier carried across');
ok((int)$payload['free_callouts_per_month'] === 12,            'free_callouts_per_month carried across');
ok((float)$payload['labour_rate_per_hr'] === 85000.0,          'labour_rate_per_hr carried across');
ok((float)$payload['parts_markup_pct'] === 25.00,              'parts_markup_pct carried across');
ok(strpos($payload['notes'], 'Contract expected') !== false,   'notes include general_notes');
ok(strpos($payload['notes'], 'Vodacom supplies spare') !== false, 'notes include spare_policy_notes');

/* ── 4. Partial-update semantics ───────────────────────────────────── */
h('4. Partial update — bump payment_terms_days only');
$origTerms = (int)$spec['payment_terms_days'];
$tss->save($tenderId, ['payment_terms_days' => 60], 999, 'Smoke Test');
$spec2 = $tss->forTender($tenderId);
ok((int)$spec2['payment_terms_days'] === 60,                   'payment_terms_days updated to 60');
ok($spec2['pm_cadence'] === 'QUARTERLY',                       'pm_cadence untouched (partial update)');
ok($spec2['spare_policy'] === 'CLIENT',                        'spare_policy untouched (partial update)');
/* Restore */
$tss->save($tenderId, ['payment_terms_days' => $origTerms], 999, 'Smoke Test');
$spec3 = $tss->forTender($tenderId);
ok((int)$spec3['payment_terms_days'] === $origTerms,           "restored payment_terms_days to $origTerms");

echo "\n=== DONE ===\nOpen: http://localhost/rsflow.dspera/Tenders/view/$tenderId\n\n";
