<?php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\LegacyPatientActivityRepository;
use App\Repositories\VisitsRepository;

final class OutpatientCashCreditParityService
{
    /** @return array<string, mixed> */
    public function run(): array
    {
        $activeBranches = BranchReadinessPolicy::blockingQaBranches();
        $deferredBranches = BranchReadinessPolicy::deferredBranches();

        $branchResults = [];
        $details = [];
        $maxDifference = 0.0;
        $failedBranches = 0;

        foreach ($activeBranches as $branch) {
            $legacyRows = (new LegacyPatientActivityRepository($branch))
                ->outpatientCashCreditToday();

            $currentRows = (new VisitsRepository($branch))
                ->outpatientCashCreditToday();

            $legacyMap = $this->toMap($legacyRows);
            $currentMap = $this->toMap($currentRows);
            $branchFailures = 0;

            foreach (['cash', 'credit'] as $category) {
                $legacyValue = (float)($legacyMap[$category] ?? 0);
                $currentValue = (float)($currentMap[$category] ?? 0);
                $difference = abs($legacyValue - $currentValue);
                $maxDifference = max($maxDifference, $difference);

                if ($difference !== 0.0) {
                    $branchFailures++;
                }

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

            if ($branchFailures > 0) {
                $failedBranches++;
            }

            $branchResults[$branch] = [
                'status' => $branchFailures === 0 ? 'PASS' : 'FAIL',
                'failures' => $branchFailures,
                'legacy_total' => array_sum($legacyMap),
                'current_total' => array_sum($currentMap),
            ];
        }

        $status = (
            count($activeBranches) === 2
            && count($details) === 4
            && $failedBranches === 0
            && $maxDifference === 0.0
        ) ? 'PASS' : 'FAIL';

        return [
            'schema_version' => '1.0',
            'phase' => 'H11.0-P5',
            'legacy_function' => 'out_cash_cr',
            'legacy_function_name' => 'get_out_patient_cash_credit',
            'source_evidence_boundary' => 'FULL_HISTORICAL_FUNCTION_BODY_RECOVERED',
            'historical_time_scope' => 'TODAY_ONLY',
            'branch_readiness_policy' => 'READY_BRANCHES_ONLY_JCKH_DEFERRED',
            'active_qa_branches' => $activeBranches,
            'deferred_branches' => $deferredBranches,
            'database_update_branches' => BranchReadinessPolicy::databaseUpdateBranches(),
            'branches_checked' => count($activeBranches),
            'value_checks' => count($details),
            'failed_branches' => $failedBranches,
            'max_difference' => $maxDifference,
            'details' => $details,
            'branch_results' => $branchResults,
            'write_operations' => 'NONE',
            'matched_promotion' => $status === 'PASS',
            'baseline_before' => [
                'known' => 31,
                'matched' => 19,
                'partial' => 9,
                'missing' => 3,
                'matched_pct' => 61.3,
            ],
            'baseline_after_live_pass' => [
                'known' => 31,
                'matched' => 20,
                'partial' => 9,
                'missing' => 2,
                'matched_pct' => 64.5,
            ],
            'status' => $status,
        ];
    }

    /**
     * @param array<int, array<string, mixed>> $rows
     * @return array<string, float>
     */
    private function toMap(array $rows): array
    {
        $out = ['cash' => 0.0, 'credit' => 0.0];

        foreach ($rows as $row) {
            $category = strtolower(trim((string)($row['category'] ?? 'credit')));
            $key = $category === 'cash' ? 'cash' : 'credit';
            $out[$key] += (float)($row['value'] ?? 0);
        }

        return $out;
    }
}
