<?php

declare(strict_types=1);

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

use App\Services\InpatientDailyRevenueService;
use App\Services\XlsxExportService;

$root = dirname(__DIR__);
$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;
}

$files = [
    'repository' => $root . '/app/Repositories/InpatientDailyRevenueRepository.php',
    'service' => $root . '/app/Services/InpatientDailyRevenueService.php',
    'controller' => $root . '/app/Controllers/InpatientDailyRevenueController.php',
    'view' => $root . '/app/Views/inpatient_daily_revenue/index.php',
    'xlsx' => $root . '/app/Services/XlsxExportService.php',
    'sql' => $root . '/database/inpatient_daily_revenue_engine.sql',
    'routes' => $root . '/public/index.php',
    'layout' => $root . '/app/Views/layouts/main.php',
    'version' => $root . '/DDB_VERSION.json',
    'oracle_contract_test' => $root . '/tools/test_inpatient_daily_revenue_oracle_contract.php',
];

$sources = [];
foreach ($files as $key => $path) {
    $sources[$key] = is_file($path) ? (string)file_get_contents($path) : '';
}

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

$missing = array_keys(array_filter($sources, static fn(string $source): bool => $source === ''));
$add('required_files_present', $missing === [], implode(' | ', $missing));
$currentRelease = (string)($version['release'] ?? '');
$currentPhase = (string)($version['phase'] ?? '');
$preservedDailyRevenueRelease = (string)($version['preserved_daily_revenue_release'] ?? '');
$preservedDailyRevenuePhase = (string)($version['preserved_daily_revenue_phase'] ?? '');
$preservedDailyRevenueContract = (string)($version['preserved_daily_revenue_contract'] ?? '');

$add(
    'release_11_0_10_5_1_or_later',
    $currentRelease !== '' && version_compare($currentRelease, '11.0.10.5.1', '>='),
    $currentRelease
);
$add(
    'daily_revenue_baseline_provenance_preserved',
    $preservedDailyRevenueRelease === '11.0.10.5.1'
        && $preservedDailyRevenuePhase === 'H11.0-P10.5-R1'
        && $preservedDailyRevenueContract === 'UNCHANGED',
    'current_phase=' . $currentPhase
        . '; preserved_release=' . $preservedDailyRevenueRelease
        . '; preserved_phase=' . $preservedDailyRevenuePhase
        . '; contract=' . $preservedDailyRevenueContract
);

$add(
    'no_direct_legacy_procedure_call',
    preg_match('/\bSP_IPD_OPD_VAT_REVENUE\s*\(/i', $sources['repository']) !== 1
        && preg_match('/\bSP_INPATIENT_REVENUE_DATA\s*\(/i', $sources['repository']) !== 1,
    'set-based repository only'
);
$add('active_inpatients_only', stripos($sources['sql'], 'bt.enddate IS NULL') !== false, 'current bed occupancy');
$add(
    'company_365_uses_first_admission_only',
    stripos($sources['sql'], 'WHEN a.financlassid = 365') !== false
        && stripos($sources['sql'], 'NVL(f.first_admission_date, a.visit_start_date)') !== false,
    '365 conditional LOS'
);
$add(
    'other_companies_use_visit_start',
    stripos($sources['sql'], 'ELSE TRUNC(SYSDATE) - TRUNC(a.visit_start_date) + 1') !== false,
    'RCP_VISIT.VISIT_START_DATE'
);
$add('ten_revenue_source_categories', preg_match_all('/\/\*\s*(?:[1-9]|10)\)/', $sources['sql']) === 10, '10 source categories');
$add(
    'no_invalid_reg_packages_in_out_pkg_reference',
    stripos($sources['repository'], 'pkg.in_out_pkg') === false
        && stripos($sources['sql'], 'pkg.in_out_pkg') === false
        && stripos($sources['repository'], 'LEFT JOIN reg_packages pkg') === false
        && stripos($sources['sql'], 'LEFT JOIN reg_packages pkg') === false,
    'closes NJCH ORA-00904 root cause'
);
$add(
    'residence_package_flag_uses_residence_transaction',
    stripos($sources['repository'], 'NVL(r.in_out_pkg, 0)') !== false
        && stripos($sources['sql'], 'NVL(r.in_out_pkg, 0)') !== false,
    'PACC_PAT_RES_TRAN alias r'
);
$add(
    'live_oracle_contract_smoke_gate_present',
    strpos($sources['repository'], 'public function validateOracleContract(): void') !== false
        && strpos($sources['repository'], 'public function oracleContractValidationSql(): string') !== false
        && strpos($sources['repository'], 'WHERE 1 = 0') !== false,
    'read-only zero-row schema parse gate'
);
$add(
    'live_oracle_contract_test_tool_present',
    strpos($sources['oracle_contract_test'], "new InpatientDailyRevenueRepository('njch')") !== false
        && strpos($sources['oracle_contract_test'], 'validateOracleContract();') !== false
        && strpos($sources['oracle_contract_test'], "'oracle_writes' => 'NONE'") !== false,
    'required target-environment ORA identifier gate'
);
$add('multi_finance_store_base_share_preserved', stripos($sources['repository'], 'WHEN ap.multi_finan_flag = 1 THEN NVL(i.finanshare1, 0)') !== false, 'legacy parity correction');
$add('multi_finance_residence_patient_share_preserved', stripos($sources['repository'], 'Legacy parity: on multi-finance residence rows') !== false, 'legacy parity correction');
$add(
    'controller_load_contract_hotfix',
    strpos($sources['controller'], 'string &$errorMessage') === false
        && substr_count($sources['controller'], '$loadResult = $this->loadReport($hospitalCode);') === 2
        && strpos($sources['controller'], "'report' =>") !== false
        && strpos($sources['controller'], "'errorMessage' =>") !== false,
    'no typed by-reference output; structured result used by index and export'
);

$add(
    'view_php74_compatible_no_match_expression',
    preg_match('/\bmatch\s*\(/', $sources['view']) !== 1,
    'PHP 8 match syntax prohibited for deployed PHP 7.x runtime'
);
$add(
    'view_method_label_lookup_preserved',
    strpos($sources['view'], '$methodLabelsAr = [') !== false
        && strpos($sources['view'], "'nhic_over_30' =>") !== false
        && strpos($sources['view'], "'cash_patient_share_per_los' =>") !== false
        && strpos($sources['view'], '$methodLabelsAr[$methodCode] ?? \'حصة الشركة ÷ مدة الإقامة\'') !== false,
    'PHP 7.4-compatible payer method label mapping'
);

$sampleRows = [
    ['financlassid' => 365, 'financial_class' => 'NHIC', 'los' => 7, 'total_los' => 30, 'patient_share_total' => 0, 'company_share_total' => 0],
    ['financlassid' => 365, 'financial_class' => 'NHIC', 'los' => 7, 'total_los' => 31, 'patient_share_total' => 0, 'company_share_total' => 0],
    ['financlassid' => 170, 'financial_class' => 'TCS', 'los' => 3, 'total_los' => 3, 'patient_share_total' => 0, 'company_share_total' => 0],
    ['financlassid' => 170, 'financial_class' => 'TCS', 'los' => 4, 'total_los' => 4, 'patient_share_total' => 0, 'company_share_total' => 0],
    ['financlassid' => 170, 'financial_class' => 'TCS', 'los' => 9, 'total_los' => 9, 'patient_share_total' => 0, 'company_share_total' => 0],
    ['financlassid' => 1, 'financial_class' => 'CASH', 'los' => 4, 'total_los' => 4, 'patient_share_total' => 7864.66, 'company_share_total' => 0],
    ['financlassid' => 777, 'financial_class' => 'INSURANCE', 'los' => 5, 'total_los' => 5, 'patient_share_total' => 0, 'company_share_total' => 12836.52],
];
$report = (new InpatientDailyRevenueService())->build($sampleRows);
$p = $report['patients'];
$add('rule_365_30_days', abs((float)$p[0]['daily_revenue'] - 4746.87) < 0.001, (string)$p[0]['daily_revenue']);
$add('rule_365_31_days', abs((float)$p[1]['daily_revenue'] - 2373.00) < 0.001, (string)$p[1]['daily_revenue']);
$add('rule_tcs_1_3', abs((float)$p[2]['daily_revenue'] - 2250.00) < 0.001, (string)$p[2]['daily_revenue']);
$add('rule_tcs_4_8', abs((float)$p[3]['daily_revenue'] - 1950.00) < 0.001, (string)$p[3]['daily_revenue']);
$add('rule_tcs_9_plus', abs((float)$p[4]['daily_revenue'] - 1750.00) < 0.001, (string)$p[4]['daily_revenue']);
$add('rule_cash_patient_share_per_los', abs((float)$p[5]['daily_revenue'] - 1966.17) < 0.001, (string)$p[5]['daily_revenue']);
$add('rule_insurance_company_share_per_los', abs((float)$p[6]['daily_revenue'] - 2567.30) < 0.001, (string)$p[6]['daily_revenue']);

$add(
    'page_and_export_routes_registered',
    strpos($sources['routes'], "case 'inpatient-daily-revenue':") !== false
        && strpos($sources['routes'], "case 'inpatient-daily-revenue-export':") !== false,
    'index + final.xlsx export'
);
$add(
    'revenue_permission_enforced',
    strpos($sources['controller'], "dashboard_role_revenue") !== false
        && strpos($sources['layout'], "'visible' => \$canAccessRevenue") !== false,
    'existing revenue role'
);
$add('professional_xlsx_dynamic_filename', strpos($sources['controller'], 'strtoupper($hospitalCode) . \'_Daily_Revenue_\' . date(\'Y-m-d\') . \'.xlsx\'') !== false, '{HOSPITAL}_Daily_Revenue_{YYYY-MM-DD}.xlsx');
$add('professional_xlsx_two_sheets', strpos($sources['xlsx'], '<sheet name="Summary"') !== false && strpos($sources['xlsx'], '<sheet name="Daily Revenue"') !== false && strpos($sources['xlsx'], '<sheet name="Detailed Audit"') === false && strpos($sources['xlsx'], '<sheet name="Needs Review"') === false, '2 sheets only');
$add('manual_style_sheet_contract', strpos($sources['xlsx'], "'Attending Doctor', 'Financial Class', 'LOS', 'Nationality', 'Patient Name', 'Patient ID'") !== false && strpos($sources['xlsx'], "'Unit Daily Revenue Total'") !== false && strpos($sources['xlsx'], "'Grand Total Daily Revenue'") !== false, 'manual familiarity + subtotals under Daily Revenue column');
$add('obsolete_export_sheet_builders_removed', strpos($sources['xlsx'], 'buildDetailedAuditSheet') === false && strpos($sources['xlsx'], 'buildNeedsReviewSheet') === false && strpos($sources['xlsx'], "'xl/worksheets/sheet3.xml'") === false && strpos($sources['xlsx'], "'xl/worksheets/sheet4.xml'") === false, 'no obsolete export sheets');
$add('native_payer_chart_contract', strpos($sources['xlsx'], 'Top Payers by Daily Revenue') !== false && strpos($sources['xlsx'], 'xl/charts/chart1.xml') !== false, 'native Excel chart');
$add('xlsx_php74_compatibility_contract', preg_match('/\bmatch\s*\(/', $sources['xlsx']) !== 1 && strpos($sources['xlsx'], '?->') === false && stripos($sources['xlsx'], 'str_contains(') === false && stripos($sources['xlsx'], 'str_starts_with(') === false && stripos($sources['xlsx'], 'str_ends_with(') === false && preg_match('/\breadonly\b|\benum\s+[A-Za-z_]/', $sources['xlsx']) !== 1, 'no PHP 8-only syntax');
$add('view_professional_export_contract', strpos($sources['view'], 'Professional finance workbook') !== false && strpos($sources['view'], 'Export Professional Excel') !== false, 'page export card');
$add('page_has_executive_kpis_and_charts', strpos($sources['view'], 'idr-kpi-grid') !== false && strpos($sources['view'], 'idr-payer-bars') !== false && strpos($sources['view'], 'idr-unit-chart') !== false, 'KPIs + payer + unit charts');

$tmp = sys_get_temp_dir() . '/ddb_idr_http_qa_' . bin2hex(random_bytes(6)) . '.xlsx';
try {
    (new XlsxExportService())->createFinalWorkbookFile($tmp, $report);
    $signature = is_file($tmp) ? (string)file_get_contents($tmp, false, null, 0, 2) : '';
    $add('xlsx_export_engine_runtime', is_file($tmp) && filesize($tmp) > 5000 && $signature === 'PK', is_file($tmp) ? (string)filesize($tmp) : 'missing');

    $archive = new PharData($tmp);
    $workbookXml = isset($archive['xl/workbook.xml']) ? (string)$archive['xl/workbook.xml']->getContent() : '';
    $dailyXml = isset($archive['xl/worksheets/sheet2.xml']) ? (string)$archive['xl/worksheets/sheet2.xml']->getContent() : '';
    $add('xlsx_runtime_two_sheets', substr_count($workbookXml, '<sheet name=') === 2 && strpos($workbookXml, 'Detailed Audit') === false && strpos($workbookXml, 'Needs Review') === false, '2 worksheets only');
    $add('xlsx_runtime_manual_daily_sheet', strpos($dailyXml, 'Unit Daily Revenue Total') !== false && strpos($dailyXml, 'Grand Total Daily Revenue') !== false, 'manual-style grouped sheet');
    $unitSubtotalMatches = preg_match_all('/<row r="(\d+)"[^>]*>.*?<c r="A\1"[^>]*>.*?Unit Daily Revenue Total.*?<\/c>.*?<c r="I\1"[^>]*t="n"><v>[^<]+<\/v><\/c>.*?<\/row>/s', $dailyXml, $unitSubtotalRows);
    $add('xlsx_runtime_unit_subtotal_under_daily_revenue_column', $unitSubtotalMatches >= 1, (string)$unitSubtotalMatches . ' unit subtotal rows in column I');
    $add('xlsx_runtime_native_chart', isset($archive['xl/charts/chart1.xml']), 'payer chart');
} catch (Throwable $e) {
    $add('xlsx_export_engine_runtime', false, $e->getMessage());
} finally {
    @unlink($tmp);
    @unlink($tmp . '.zip');
}

$add('oracle_writes_none', (string)($version['oracle_write_operations'] ?? '') === 'NONE', 'read-only');
$add('database_schema_changes_none', (string)($version['database_changes'] ?? '') === 'NONE', 'no DDL');

$failures = count(array_filter($checks, static fn(array $check): bool => $check['status'] === 'FAIL'));
$result = [
    'schema_version' => '1.0',
    'phase' => 'H11.0-P10.5-R1',
    'release' => (string)($version['release'] ?? ''),
    'title' => 'Daily Revenue Workbook Simplification & Unit Subtotal Alignment',
    'calculation_mode' => 'SET_BASED_CURRENT_INPATIENTS',
    'direct_legacy_procedure_call' => false,
    'revenue_source_categories' => 10,
    'export_filename_pattern' => '{HOSPITAL}_Daily_Revenue_{YYYY-MM-DD}.xlsx',
    'oracle_writes' => 'NONE',
    'live_oracle_runtime_verification' => 'REQUIRED_ON_NJCH_ENVIRONMENT',
    'checks' => $checks,
    '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);
