<?php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\DiagnosticsRepository;
use App\Repositories\LegacyDiagnosticsRepository;

final class DiagnosticsParityService
{
    /** @var string */
    private $hospitalCode;

    /** @var LegacyDiagnosticsRepository */
    private $legacy;

    /** @var DiagnosticsRepository */
    private $current;

    public function __construct(string $hospitalCode)
    {
        $this->hospitalCode = strtolower($hospitalCode);
        $this->legacy = new LegacyDiagnosticsRepository($this->hospitalCode);
        $this->current = new DiagnosticsRepository($this->hospitalCode);
    }

    /** @return array<string, mixed> */
    public function run(int $year, int $compareYear, string $fromDate, string $toDate): array
    {
        $yearLab = $this->compareMonthly(
            'plts_s',
            $this->legacy->monthlyLabTests($year, $compareYear),
            $this->current->monthlyLabTests($year, $compareYear)
        );
        $yearRadiology = $this->compareMonthly(
            'prts_s',
            $this->legacy->monthlyRadiologyTests($year, $compareYear),
            $this->current->monthlyRadiologyTests($year, $compareYear)
        );
        $rangeLab = $this->compareMonthly(
            'plts_s',
            $this->legacy->monthlyLabTests($year, $compareYear, $fromDate, $toDate),
            $this->current->monthlyLabTests($year, $compareYear, $fromDate, $toDate)
        );
        $rangeRadiology = $this->compareMonthly(
            'prts_s',
            $this->legacy->monthlyRadiologyTests($year, $compareYear, $fromDate, $toDate),
            $this->current->monthlyRadiologyTests($year, $compareYear, $fromDate, $toDate)
        );

        $functions = [$yearLab, $yearRadiology, $rangeLab, $rangeRadiology];
        $failures = count(array_filter($functions, static function (array $row): bool {
            return ($row['status'] ?? 'FAIL') !== 'PASS';
        }));
        $maxDifference = 0.0;
        foreach ($functions as $row) {
            $maxDifference = max(
                $maxDifference,
                (float)($row['current_total_difference'] ?? 0),
                (float)($row['compare_total_difference'] ?? 0),
                (float)($row['max_month_difference'] ?? 0)
            );
        }

        return [
            'schema_version' => '1.0',
            'phase' => '10.12',
            'hospital' => strtoupper($this->hospitalCode),
            'year' => $year,
            'compare_year' => $compareYear,
            'range_from' => $fromDate,
            'range_to' => $toDate,
            'write_operations' => 'NONE',
            'source_contract' => [
                'plts_s' => 'RCP_LAB_SERVICE_RESERVATION; EXPECTEDDONEDATE <= SYSDATE; grouped by calendar month.',
                'prts_s' => 'RCP_RAD_SERVICE_RESERVATION; MACHINE_SCH_FROM <= SYSDATE; grouped by calendar month.',
                'date_range_rule' => 'Inclusive current date window compared with the same month/day window shifted to compare year.',
                'multi_branch_note' => 'Legacy multi-branch plts/prts remain PARTIAL; this phase proves selected-branch plts_s/prts_s parity.',
            ],
            'modes' => [
                'year' => ['functions' => [$yearLab, $yearRadiology]],
                'date_range' => ['functions' => [$rangeLab, $rangeRadiology]],
            ],
            'functions_checked' => 4,
            'max_difference' => $maxDifference,
            'failures' => $failures,
            'status' => $failures === 0 && $maxDifference === 0.0 ? 'PASS' : 'FAIL',
        ];
    }

    /**
     * @param array<int, array<string, mixed>> $legacyRows
     * @param array<int, array<string, mixed>> $currentRows
     * @return array<string, mixed>
     */
    private function compareMonthly(string $legacyFunction, array $legacyRows, array $currentRows): array
    {
        $legacyByMonth = [];
        foreach ($legacyRows as $row) {
            $legacyByMonth[(int)($row['month_id'] ?? 0)] = $row;
        }
        $currentByMonth = [];
        foreach ($currentRows as $row) {
            $currentByMonth[(int)($row['month_id'] ?? 0)] = $row;
        }

        $details = [];
        $legacyCurrentTotal = 0.0;
        $newCurrentTotal = 0.0;
        $legacyCompareTotal = 0.0;
        $newCompareTotal = 0.0;
        $maxDifference = 0.0;
        $ok = true;

        for ($month = 1; $month <= 12; $month++) {
            $legacy = $legacyByMonth[$month] ?? [];
            $current = $currentByMonth[$month] ?? [];
            $legacyCurrent = (float)($legacy['current_value'] ?? 0);
            $newCurrent = (float)($current['current_value'] ?? 0);
            $legacyCompare = (float)($legacy['compare_value'] ?? 0);
            $newCompare = (float)($current['compare_value'] ?? 0);
            $currentDifference = abs($legacyCurrent - $newCurrent);
            $compareDifference = abs($legacyCompare - $newCompare);
            $monthOk = $currentDifference === 0.0 && $compareDifference === 0.0;
            if (!$monthOk) {
                $ok = false;
            }
            $maxDifference = max($maxDifference, $currentDifference, $compareDifference);
            $legacyCurrentTotal += $legacyCurrent;
            $newCurrentTotal += $newCurrent;
            $legacyCompareTotal += $legacyCompare;
            $newCompareTotal += $newCompare;
            $details[] = [
                'month_id' => $month,
                'month_name' => (string)($current['month_name'] ?? $legacy['month_name'] ?? ''),
                'legacy_current' => $legacyCurrent,
                'new_current' => $newCurrent,
                'current_difference' => $currentDifference,
                'legacy_compare' => $legacyCompare,
                'new_compare' => $newCompare,
                'compare_difference' => $compareDifference,
                'status' => $monthOk ? 'PASS' : 'FAIL',
            ];
        }

        return [
            'legacy_function' => $legacyFunction,
            'comparison_type' => 'monthly_two_series',
            'legacy_rows' => count($legacyRows),
            'new_rows' => count($currentRows),
            'legacy_current_total' => $legacyCurrentTotal,
            'new_current_total' => $newCurrentTotal,
            'legacy_compare_total' => $legacyCompareTotal,
            'new_compare_total' => $newCompareTotal,
            'current_total_difference' => abs($legacyCurrentTotal - $newCurrentTotal),
            'compare_total_difference' => abs($legacyCompareTotal - $newCompareTotal),
            'max_month_difference' => $maxDifference,
            'months' => $details,
            'status' => $ok ? 'PASS' : 'FAIL',
        ];
    }
}
