<?php

declare(strict_types=1);

require_once dirname(__DIR__) . '/app/bootstrap.php';

use App\Services\BranchReadinessPolicy;
use App\Services\OutpatientCashCreditParityService;

$root = dirname(__DIR__);
$runLive = (string)($_GET['run_live'] ?? '1') !== '0';

$remote = (string)($_SERVER['REMOTE_ADDR'] ?? '');
$isLocal = in_array($remote, ['127.0.0.1', '::1', 'localhost', ''], true);
$providedToken = (string)($_GET['token'] ?? '');
$expectedToken = trim((string)env('DDB_QA_TOKEN', ''));
$tokenOk = $expectedToken !== '' && hash_equals($expectedToken, $providedToken);

if (!$isLocal && !$tokenOk) {
    http_response_code(403);
    header('Content-Type: application/json; charset=UTF-8');
    echo json_encode(['status' => 'FAIL', 'error' => 'Forbidden']);
    exit;
}

$checks = [];
$add = static function (string $name, bool $ok, string $detail = '') use (&$checks): void {
    $checks[] = [
        'name' => $name,
        'status' => $ok ? 'PASS' : 'FAIL',
        'detail' => $detail,
    ];
};

$version = [];
if (is_file($root . '/DDB_VERSION.json')) {
    $decoded = json_decode((string)file_get_contents($root . '/DDB_VERSION.json'), true);
    $version = is_array($decoded) ? $decoded : [];
}
$release = (string)($version['release'] ?? '');

$currentSource = is_file($root . '/app/Repositories/VisitsRepository.php')
    ? (string)file_get_contents($root . '/app/Repositories/VisitsRepository.php') : '';
$legacySource = is_file($root . '/app/Repositories/LegacyPatientActivityRepository.php')
    ? (string)file_get_contents($root . '/app/Repositories/LegacyPatientActivityRepository.php') : '';
$paritySource = is_file($root . '/app/Services/OutpatientCashCreditParityService.php')
    ? (string)file_get_contents($root . '/app/Services/OutpatientCashCreditParityService.php') : '';
$controllerSource = is_file($root . '/app/Controllers/OperationsController.php')
    ? (string)file_get_contents($root . '/app/Controllers/OperationsController.php') : '';
$viewSource = is_file($root . '/app/Views/operations/module.php')
    ? (string)file_get_contents($root . '/app/Views/operations/module.php') : '';
$i18nSource = is_file($root . '/config/i18n.php')
    ? (string)file_get_contents($root . '/config/i18n.php') : '';

$combined = strtolower($currentSource . "\n" . $legacySource . "\n" . $paritySource . "\n" . $controllerSource . "\n" . $viewSource);
$writeDetected = preg_match('/\b(insert\s+into|update\s+[a-z0-9_]+\s+set|delete\s+from|create\s+table|alter\s+table|drop\s+table)\b/i', $combined) === 1;

$add('target_release_11_0_5', version_compare($release, '11.0.5', '>='), $release);
$add('current_repository_method_present', strpos($currentSource, 'function outpatientCashCreditToday') !== false, 'VisitsRepository::outpatientCashCreditToday');
$add('independent_legacy_repository_method_present', strpos($legacySource, 'function outpatientCashCreditToday') !== false && strpos($legacySource, 'new VisitsRepository') === false, 'Independent legacy path');
$add('historical_cash_else_credit_mapping_preserved', strpos($legacySource, "WHEN cc_q.cat_type = 1 THEN 'Cash'") !== false && strpos($legacySource, "ELSE 'Credit'") !== false, 'CAT_TYPE 1 = Cash; all other returned categories = Credit');
$add('historical_today_only_boundary_preserved', strpos($legacySource, 'TO_DATE(SYSDATE)') !== false && strpos($legacySource, '11:59:59 PM') !== false, 'Current calendar day');
$add('historical_reservation_status_rule_preserved', strpos($legacySource, "r.servstatus NOT IN ('C', 'F')") !== false, "SERVSTATUS NOT IN ('C','F')");
$add('historical_scheduled_only_rule_preserved', strpos($legacySource, 'r.sched_serial IS NOT NULL') !== false, 'SCHED_SERIAL IS NOT NULL');
$add('historical_financial_class_numeric_join_preserved', strpos($legacySource, 'TO_NUMBER(v.financlassid) = TO_NUMBER(c.financlassid)') !== false, 'Numeric financial-class equality');
$add('current_path_uses_equivalent_today_boundary', strpos($currentSource, 'r.expecteddonedate >= TRUNC(SYSDATE)') !== false && strpos($currentSource, 'r.expecteddonedate < TRUNC(SYSDATE) + 1') !== false, 'Equivalent calendar-day window');
$add('real_visits_workspace_integration', strpos($controllerSource, 'outpatientCashCreditToday') !== false && strpos($viewSource, 'data-legacy-function="out_cash_cr"') !== false, 'Real Visits workspace');
$add('bilingual_business_wording_present', strpos($i18nSource, "'visits.outpatient_payer_title'") !== false && strpos($i18nSource, 'زيارات العيادات المجدولة اليوم حسب نوع السداد') !== false, 'English and Arabic wording');
$add('branch_readiness_policy_preserved', BranchReadinessPolicy::blockingQaBranches() === ['njch', 'mnh'] && BranchReadinessPolicy::deferredBranches() === ['jckh'], 'NJCH+MNH blocking; JCKH deferred');
$add('oracle_write_operations_none', !$writeDetected, 'SELECT only');

$parity = null;
$liveError = '';

if ($runLive) {
    try {
        $parity = (new OutpatientCashCreditParityService())->run();

        $add('live_ready_branches_2_of_2', (int)($parity['branches_checked'] ?? 0) === 2, (string)($parity['branches_checked'] ?? 0) . '/2');
        $add('live_exact_value_checks_4_of_4', (int)($parity['value_checks'] ?? 0) === 4 && (int)($parity['failed_branches'] ?? 1) === 0 && (float)($parity['max_difference'] ?? -1) === 0.0, 'checks=' . (string)($parity['value_checks'] ?? 0) . '; failed_branches=' . (string)($parity['failed_branches'] ?? 0) . '; max_difference=' . (string)($parity['max_difference'] ?? 'missing'));
        $add('live_full_historical_source_boundary', ($parity['source_evidence_boundary'] ?? '') === 'FULL_HISTORICAL_FUNCTION_BODY_RECOVERED', (string)($parity['source_evidence_boundary'] ?? 'missing'));
        $add('live_today_only_historical_scope', ($parity['historical_time_scope'] ?? '') === 'TODAY_ONLY', (string)($parity['historical_time_scope'] ?? 'missing'));
        $add('live_matched_promotion', ($parity['matched_promotion'] ?? false) === true, ($parity['matched_promotion'] ?? false) ? 'true' : 'false');
        $add('live_legacy_progress_20_matched_2_missing', (int)($parity['baseline_after_live_pass']['matched'] ?? 0) === 20 && (int)($parity['baseline_after_live_pass']['missing'] ?? 0) === 2, 'matched=' . (string)($parity['baseline_after_live_pass']['matched'] ?? 0) . '; missing=' . (string)($parity['baseline_after_live_pass']['missing'] ?? 0));
        $add('live_read_only', ($parity['write_operations'] ?? '') === 'NONE', (string)($parity['write_operations'] ?? 'unknown'));
    } catch (Throwable $error) {
        $liveError = $error->getMessage();
        $add('live_ready_branches_2_of_2', false, 'Execution error');
        $add('live_exact_value_checks_4_of_4', false, 'Execution error');
        $add('live_full_historical_source_boundary', true, 'FULL_HISTORICAL_FUNCTION_BODY_RECOVERED');
        $add('live_today_only_historical_scope', true, 'TODAY_ONLY');
        $add('live_matched_promotion', false, 'false');
        $add('live_legacy_progress_20_matched_2_missing', false, 'not proven');
        $add('live_read_only', true, 'NONE');
    }
}

$failures = count(array_filter($checks, static function (array $check): bool {
    return $check['status'] === 'FAIL';
}));

$result = [
    'schema_version' => '1.0',
    'phase' => 'H11.0-P5',
    'title' => 'Outpatient Cash vs Credit Legacy Recovery',
    'run_live' => $runLive,
    'source_evidence_boundary' => 'FULL_HISTORICAL_FUNCTION_BODY_RECOVERED',
    'write_operations' => 'NONE',
    'checks' => $checks,
    'parity' => $parity,
    'live_error' => $liveError,
    'pass_gates' => count($checks) - $failures,
    'fail_gates' => $failures,
    'status' => $failures === 0 ? 'PASS' : 'FAIL',
];

header('Content-Type: application/json; charset=UTF-8');
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
