<?php

declare(strict_types=1);

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

use App\Core\Database;
use App\Repositories\DoctorsRepository;
use App\Services\FairYearComparisonPolicy;

$hospital = strtolower((string)($argv[1] ?? 'njch'));
$year = (int)($argv[2] ?? date('Y'));
$compareYear = (int)($argv[3] ?? ($year - 1));
$requested = trim((string)($argv[4] ?? ''));

$contract = (new FairYearComparisonPolicy())->resolve($year, $compareYear);
$startMonth = (int)($contract['start_month'] ?? 1);
$endMonth = (int)($contract['end_month'] ?? 12);

$buildFilter = static function (array $ids, string $prefix = ''): array {
    $parts = [];
    $params = [];
    foreach (array_values($ids) as $index => $id) {
        if (!preg_match('/^-?\d+$/', (string)$id)) {
            throw new RuntimeException('LIVE_INVALID_SPECIALTY_ID');
        }
        $key = 'legacy_specialty_' . $index;
        $parts[] = ':' . $key;
        $params[$key] = (int)$id;
    }
    return [
        'sql' => $parts === []
            ? ''
            : 'AND ' . $prefix . 'SPECIAL_SPEC_ID IN (' . implode(', ', $parts) . ')',
        'params' => $params,
    ];
};

$monthFilter = static function (int $start, int $end): string {
    return ($start === 1 && $end === 12)
        ? ''
        : 'AND MONTHID BETWEEN :start_month AND :end_month';
};

$monthParams = static function (int $start, int $end): array {
    return ($start === 1 && $end === 12)
        ? []
        : ['start_month' => $start, 'end_month' => $end];
};

$referenceSummary = static function (
    string $hospitalCode,
    int $currentYear,
    int $priorYear,
    int $start,
    int $end,
    array $ids
) use ($buildFilter, $monthFilter, $monthParams): array {
    $filter = $buildFilter($ids);
    $months = $monthFilter($start, $end);
    $sql = "
        WITH p AS (
            SELECT :current_year current_year, :compare_year compare_year
            FROM dual
        ),
        per_doctor AS (
            SELECT
                YEARID,
                EMP_ID doctor_key,
                NVL(SUM(DISTINCT NVL(TOTAL_OP_VISITS, 0)), 0) op_visits,
                NVL(SUM(DISTINCT NVL(TOTAL_INPAT_VISITS, 0)), 0) admissions,
                NVL(SUM(DISTINCT NVL(TOT_REV, 0)), 0) revenue,
                NVL(SUM(DISTINCT NVL(MOH, 0)), 0) moh,
                NVL(SUM(DISTINCT NVL(DRUG_REV, 0)), 0) drug,
                NVL(SUM(DISTINCT NVL(NET_REV_AFTER_DRUG_MOH, 0)), 0) net
            FROM KPI_DOCTOR_PERF_DETAIL_JOB
            CROSS JOIN p
            WHERE YEARID IN (p.current_year, p.compare_year)
              {$months}
              {$filter['sql']}
            GROUP BY YEARID, EMP_ID
        )
        SELECT
            NVL(SUM(CASE WHEN YEARID = p.current_year THEN op_visits ELSE 0 END), 0) current_op_visits,
            NVL(SUM(CASE WHEN YEARID = p.compare_year THEN op_visits ELSE 0 END), 0) compare_op_visits,
            NVL(SUM(CASE WHEN YEARID = p.current_year THEN admissions ELSE 0 END), 0) current_inpat_visits,
            NVL(SUM(CASE WHEN YEARID = p.compare_year THEN admissions ELSE 0 END), 0) compare_inpat_visits,
            NVL(SUM(CASE WHEN YEARID = p.current_year THEN revenue ELSE 0 END), 0) current_revenue,
            NVL(SUM(CASE WHEN YEARID = p.compare_year THEN revenue ELSE 0 END), 0) compare_revenue,
            NVL(SUM(CASE WHEN YEARID = p.current_year THEN moh ELSE 0 END), 0) current_moh,
            NVL(SUM(CASE WHEN YEARID = p.compare_year THEN moh ELSE 0 END), 0) compare_moh,
            NVL(SUM(CASE WHEN YEARID = p.current_year THEN drug ELSE 0 END), 0) current_drug,
            NVL(SUM(CASE WHEN YEARID = p.current_year THEN net ELSE 0 END), 0) current_net,
            COUNT(DISTINCT CASE WHEN YEARID = p.current_year THEN doctor_key END) active_doctors
        FROM per_doctor
        CROSS JOIN p
    ";
    $params = array_merge(
        [
            'current_year' => $currentYear,
            'compare_year' => $priorYear,
        ],
        $monthParams($start, $end),
        $filter['params']
    );
    $row = Database::fetchOne($hospitalCode, $sql, $params);
    $fields = [
        'current_op_visits',
        'compare_op_visits',
        'current_inpat_visits',
        'compare_inpat_visits',
        'current_revenue',
        'compare_revenue',
        'current_moh',
        'compare_moh',
        'current_drug',
        'current_net',
        'active_doctors',
    ];
    $out = [];
    foreach ($fields as $field) {
        $out[$field] = (float)($row[$field] ?? 0);
    }
    return $out;
};

$referenceTop = static function (
    string $hospitalCode,
    int $reportYear,
    int $start,
    int $end,
    array $ids
) use ($buildFilter, $monthFilter, $monthParams): array {
    $filter = $buildFilter($ids);
    $months = $monthFilter($start, $end);
    $sql = "
        SELECT doctor_key, doctor_name, specialty_name, metric_value
        FROM (
            SELECT
                EMP_ID doctor_key,
                MAX(EMP_EN_DATA) doctor_name,
                MAX(SPECIAL_SPEC_EN_NAME) specialty_name,
                NVL(SUM(DISTINCT NVL(TOT_REV, 0)), 0) metric_value
            FROM KPI_DOCTOR_PERF_DETAIL_JOB
            WHERE YEARID = :legacy_year
              {$months}
              {$filter['sql']}
            GROUP BY EMP_ID
            HAVING NVL(SUM(DISTINCT NVL(TOT_REV, 0)), 0) > 0
            ORDER BY NVL(SUM(DISTINCT NVL(TOT_REV, 0)), 0) DESC, EMP_ID
        )
        WHERE ROWNUM <= 10
    ";
    $params = array_merge(
        ['legacy_year' => $reportYear],
        $monthParams($start, $end),
        $filter['params']
    );
    $rows = Database::fetchAll($hospitalCode, $sql, $params);
    return array_map(static function (array $row): array {
        return [
            'id' => trim((string)($row['doctor_key'] ?? '')),
            'label' => trim((string)($row['doctor_name'] ?? '')),
            'secondary' => trim((string)($row['specialty_name'] ?? '')),
            'value' => (float)($row['metric_value'] ?? 0),
        ];
    }, $rows);
};

$compareRows = static function (array $actual, array $expected): array {
    $differences = [];
    $max = max(count($actual), count($expected));
    for ($i = 0; $i < $max; $i++) {
        $a = $actual[$i] ?? null;
        $e = $expected[$i] ?? null;
        if ($a === null || $e === null) {
            $differences[] = ['position' => $i + 1, 'reason' => 'row_count'];
            continue;
        }
        $valueDifference = abs((float)$a['value'] - (float)$e['value']);
        if (
            (string)$a['id'] !== (string)$e['id']
            || $valueDifference !== 0.0
        ) {
            $differences[] = [
                'position' => $i + 1,
                'actual_id' => (string)$a['id'],
                'expected_id' => (string)$e['id'],
                'actual_value' => (float)$a['value'],
                'expected_value' => (float)$e['value'],
                'difference' => $valueDifference,
            ];
        }
    }
    return $differences;
};

try {
    $repo = new DoctorsRepository($hospital);
    $available = $repo->availableSpecialties(
        $year,
        $compareYear,
        $startMonth,
        $endMonth
    );

    $availableIds = array_map(static function (array $row): string {
        return (string)($row['id'] ?? '');
    }, $available);

    $selected = [];
    if ($requested !== '') {
        foreach (explode(',', $requested) as $id) {
            $id = trim($id);
            if ($id !== '' && in_array($id, $availableIds, true)) {
                $selected[] = $id;
            }
        }
    }
    if ($selected === []) {
        $selected = array_slice($availableIds, 0, min(2, count($availableIds)));
    }

    $selectedLabels = [];
    foreach ($available as $row) {
        if (in_array((string)$row['id'], $selected, true)) {
            $selectedLabels[] = (string)$row['label'];
        }
    }

    $actualSummary = $repo->summary(
        $year,
        $compareYear,
        $startMonth,
        $endMonth,
        $selected
    );
    $expectedSummary = $referenceSummary(
        $hospital,
        $year,
        $compareYear,
        $startMonth,
        $endMonth,
        $selected
    );

    $summaryDifferences = [];
    foreach ($expectedSummary as $field => $expectedValue) {
        $actualValue = (float)($actualSummary[$field] ?? 0);
        if (abs($actualValue - $expectedValue) !== 0.0) {
            $summaryDifferences[$field] = [
                'actual' => $actualValue,
                'expected' => $expectedValue,
                'difference' => abs($actualValue - $expectedValue),
            ];
        }
    }

    $actualCurrentTop = $repo->topDoctors(
        $year,
        'TOT_REV',
        10,
        $startMonth,
        $endMonth,
        $selected
    );
    $expectedCurrentTop = $referenceTop(
        $hospital,
        $year,
        $startMonth,
        $endMonth,
        $selected
    );
    $actualCompareTop = $repo->topDoctors(
        $compareYear,
        'TOT_REV',
        10,
        $startMonth,
        $endMonth,
        $selected
    );
    $expectedCompareTop = $referenceTop(
        $hospital,
        $compareYear,
        $startMonth,
        $endMonth,
        $selected
    );

    $currentTopDifferences = $compareRows(
        $actualCurrentTop,
        $expectedCurrentTop
    );
    $compareTopDifferences = $compareRows(
        $actualCompareTop,
        $expectedCompareTop
    );

    $unfiltered = $repo->summary(
        $year,
        $compareYear,
        $startMonth,
        $endMonth,
        []
    );

    $checks = [
        'specialty_options_present' => count($available) > 0,
        'multi_select_exercised' => count($selected) >= min(2, count($available)),
        'selected_ids_are_available' => count(array_diff($selected, $availableIds)) === 0,
        'filtered_summary_exact' => $summaryDifferences === [],
        'current_ranking_exact' => $currentTopDifferences === [],
        'comparison_ranking_exact' => $compareTopDifferences === [],
        'filtered_current_revenue_not_above_all' =>
            (float)$actualSummary['current_revenue']
            <= (float)$unfiltered['current_revenue'],
        'filtered_current_opd_not_above_all' =>
            (float)$actualSummary['current_op_visits']
            <= (float)$unfiltered['current_op_visits'],
        'filtered_current_admissions_not_above_all' =>
            (float)$actualSummary['current_inpat_visits']
            <= (float)$unfiltered['current_inpat_visits'],
        'filtered_active_doctors_not_above_all' =>
            (float)$actualSummary['active_doctors']
            <= (float)$unfiltered['active_doctors'],
    ];

    $failed = [];
    foreach ($checks as $name => $passed) {
        if (!$passed) {
            $failed[] = $name;
        }
    }

    $result = [
        'schema' => 'DDB_DOCTORS_SPECIALTY_FILTER_PARITY_V1',
        'captured_at' => date(DATE_ATOM),
        'hospital' => strtoupper($hospital),
        'year' => $year,
        'compare_year' => $compareYear,
        'start_month' => $startMonth,
        'end_month' => $endMonth,
        'comparison_contract' => $contract,
        'available_specialties' => count($available),
        'selected_specialty_ids' => $selected,
        'selected_specialty_labels' => $selectedLabels,
        'filtered_summary' => $actualSummary,
        'summary_differences' => $summaryDifferences,
        'current_ranking_differences' => $currentTopDifferences,
        'comparison_ranking_differences' => $compareTopDifferences,
        'checks' => $checks,
        'failed' => $failed,
        'status' => $failed === [] ? 'PASS' : 'FAIL',
        'oracle_writes' => 'NONE',
    ];
} catch (Throwable $error) {
    $result = [
        'schema' => 'DDB_DOCTORS_SPECIALTY_FILTER_PARITY_V1',
        'captured_at' => date(DATE_ATOM),
        'hospital' => strtoupper($hospital),
        'status' => 'FAIL',
        'failed' => ['live_execution'],
        'error' => preg_replace('/\s+/', ' ', $error->getMessage()),
        'oracle_writes' => 'NONE',
    ];
}

$dir = dirname(__DIR__) . '/storage/evidence/doctors';
if (!is_dir($dir) && !mkdir($dir, 0775, true) && !is_dir($dir)) {
    throw new RuntimeException('Cannot create Doctors evidence directory.');
}
$file = $dir
    . '/DOCTORS_R45_P13_SPECIALTY_FILTER_LIVE_ACCEPTANCE_'
    . date('Ymd_His')
    . '.json';
file_put_contents(
    $file,
    json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES),
    LOCK_EX
);
echo json_encode(
    $result + ['evidence_file' => $file],
    JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
), PHP_EOL;
exit(($result['status'] ?? 'FAIL') === 'PASS' ? 0 : 1);
