<?php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\LegacyMultiBranchPatientActivityRepository;

final class MultiBranchOutpatientParityService
{
    /** @var MultiBranchPatientActivityService */
    private $current;

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

    public function __construct()
    {
        $this->current = new MultiBranchPatientActivityService();
        $this->legacy = new LegacyMultiBranchPatientActivityRepository();
    }

    /** @return array<string, mixed> */
    public function run(int $year, string $fromDate, string $toDate): array
    {
        $yearResult = $this->compare(
            'year',
            $this->legacy->monthlyOutpatientVisits($year),
            $this->current->monthlyOutpatientVisits($year)
        );

        $rangeResult = $this->compare(
            'date_range',
            $this->legacy->monthlyOutpatientVisits($year, $fromDate, $toDate),
            $this->current->monthlyOutpatientVisits($year, $fromDate, $toDate)
        );

        $rows = [$yearResult, $rangeResult];
        $failures = count(array_filter($rows, static function (array $row): bool {
            return ($row['status'] ?? 'FAIL') !== 'PASS';
        }));

        return [
            'schema_version' => '1.0',
            'phase' => 'H11.0-P4',
            'legacy_function' => 'gmov',
            'legacy_function_name' => 'get_monthly_outpatient_visits',
            'branches' => ['njch', 'jckh', 'mnh'],
            'source_evidence_boundary' => 'FULL_HISTORICAL_FUNCTION_BODY_RECOVERED',
            'contract' => [
                'classcode' => 2,
                'emergency_exclusion' => false,
                'reservation_status_rule' => "SERVSTATUS NOT IN ('C','F')",
                'scheduled_rule' => 'SCHED_SERIAL IS NOT NULL',
                'branch_execution_rule' => 'same SQL independently against NJCH, JCKH, and MNH',
            ],
            'modes' => [
                'year' => ['function' => $yearResult],
                'date_range' => ['function' => $rangeResult],
            ],
            'functions_checked' => count($rows),
            'failures' => $failures,
            'write_operations' => 'NONE',
            'status' => $failures === 0 ? 'PASS' : 'FAIL',
        ];
    }

    /**
     * @param array<int, array<string, mixed>> $legacyRows
     * @param array<int, array<string, mixed>> $currentRows
     * @return array<string, mixed>
     */
    private function compare(string $mode, array $legacyRows, array $currentRows): array
    {
        $branches = ['njch', 'jckh', 'mnh'];
        $details = [];
        $maxDifference = 0.0;
        $ok = count($legacyRows) === 12 && count($currentRows) === 12;

        for ($month = 1; $month <= 12; $month++) {
            $legacy = $legacyRows[$month - 1] ?? [];
            $current = $currentRows[$month - 1] ?? [];

            foreach ($branches as $branch) {
                $legacyValue = (float)($legacy[$branch] ?? 0);
                $currentValue = (float)($current[$branch] ?? 0);
                $difference = abs($legacyValue - $currentValue);
                $maxDifference = max($maxDifference, $difference);

                if ($difference !== 0.0) {
                    $ok = false;
                }

                $details[] = [
                    'month_id' => $month,
                    'branch' => $branch,
                    'legacy_value' => $legacyValue,
                    'current_value' => $currentValue,
                    'difference' => $difference,
                    'status' => $difference === 0.0 ? 'PASS' : 'FAIL',
                ];
            }
        }

        return [
            'mode' => $mode,
            'legacy_function' => 'gmov',
            'comparison_type' => '12_months_x_3_branches',
            'legacy_rows' => count($legacyRows),
            'current_rows' => count($currentRows),
            'value_checks' => count($details),
            'max_difference' => $maxDifference,
            'details' => $details,
            'status' => $ok ? 'PASS' : 'FAIL',
        ];
    }
}
