<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Request;
use App\Core\View;
use App\Repositories\SpecialtyFinanceRepository;
use App\Services\ChartDataService;
use Throwable;

final class SpecialtyFinanceController
{
    public function index(): void
    {
        Auth::requireLogin();

        $user = Auth::user();
        if ((int)($user['dashboard_role_revenue'] ?? 0) !== 1) {
            http_response_code(403);
            View::render('errors/403', [
                'title' => current_lang() === 'ar' ? 'غير مصرح بالدخول' : 'Access not available',
                'activePage' => '',
            ]);
            return;
        }

        $hospitalCode = Auth::hospital();
        $hospital = \config('hospitals.' . $hospitalCode, []);
        $currentYear = (int)date('Y');
        $yearRequested = Request::get('year') !== null;
        $compareRequested = Request::get('compare_year') !== null;
        $year = \safe_int(Request::get('year'), $currentYear);
        $compareYear = \safe_int(Request::get('compare_year'), $year - 1);

        $repo = new SpecialtyFinanceRepository($hospitalCode);
        $years = [];
        try {
            $years = $repo->availableYears(20);
            if (!$yearRequested && !empty($years)) {
                $year = (int)$years[0];
            }
            if (!$compareRequested) {
                $compareYear = $this->defaultCompareYear($years, $year);
            }
        } catch (Throwable $e) {
            $this->logError('Specialty Finance filter discovery warning', $e);
        }

        $financeData = null;
        $dataError = null;
        try {
            $financeData = $this->buildData($repo, $year, $compareYear, $years);
        } catch (Throwable $e) {
            $dataError = $e->getMessage();
            $this->logError('Specialty Finance workspace error', $e);
        }

        View::render('specialty_finance/index', [
            'title' => current_lang() === 'ar' ? 'المالية حسب التخصص' : 'Specialty Finance',
            'activePage' => 'specialty-finance',
            'hospital' => $hospital,
            'hospitalCode' => $hospitalCode,
            'year' => $year,
            'compareYear' => $compareYear,
            'financeData' => $financeData,
            'dataError' => $dataError,
        ]);
    }

    /** @param array<int,int> $years */
    private function defaultCompareYear(array $years, int $year): int
    {
        foreach ($years as $candidate) {
            $candidate = (int)$candidate;
            if ($candidate > 0 && $candidate < $year) {
                return $candidate;
            }
        }
        return $year - 1;
    }

    /** @param array<int,int> $years @return array<string,mixed> */
    private function buildData(SpecialtyFinanceRepository $repo, int $year, int $compareYear, array $years): array
    {
        $chartService = new ChartDataService();
        $summary = $repo->summary($year, $compareYear);
        $moh = $repo->specialtyRanking($year, 'MOH', 10);
        $drug = $repo->specialtyRanking($year, 'DRUG_REV', 10);
        $net = $repo->specialtyNetRevenueRanking($year);
        $totalRevenueBySpecialty = $repo->specialtyTotalRevenueRanking($year);
        $matrix = $this->mergeExactLegacySpecialtyMetricsIntoMatrix(
            $repo->specialtyMatrix($year, 12),
            $totalRevenueBySpecialty,
            $net
        );

        $cards = [
            'moh' => $this->card('MOH revenue', (float)$summary['current_moh'], (float)$summary['compare_moh'], $chartService),
            'drug' => $this->card('Drug revenue', (float)$summary['current_drug'], (float)$summary['compare_drug'], $chartService),
            'net' => $this->card('Net after drug / MOH', (float)$summary['current_net'], (float)$summary['compare_net'], $chartService),
        ];

        $movements = [];
        foreach ($cards as $key => $card) {
            if ($card['percent'] !== null) {
                $movements[] = ['key' => $key, 'title' => $card['title'], 'percent' => (float)$card['percent']];
            }
        }
        usort($movements, static function (array $a, array $b): int {
            return abs($b['percent']) <=> abs($a['percent']);
        });

        return [
            'summary' => $summary,
            'cards' => $cards,
            'availableYears' => $years,
            'rankings' => [
                'moh' => $moh,
                'drug' => $drug,
                'net' => $net,
                'total_revenue' => $totalRevenueBySpecialty,
            ],
            'matrix' => $matrix,
            'primaryMovement' => $movements[0] ?? null,
            'topNetSpecialty' => $net[0] ?? null,
            'topTotalRevenueSpecialty' => $totalRevenueBySpecialty[0] ?? null,
            'charts' => [
                'moh' => ['title' => 'MOH contribution by specialty', 'payload' => $this->payload('MOH contribution by specialty', $moh, 'MOH revenue')],
                'drug' => ['title' => 'Drug revenue by specialty', 'payload' => $this->payload('Drug revenue by specialty', $drug, 'Drug revenue')],
                'net' => ['title' => 'Net revenue by specialty', 'payload' => $this->payload('Net revenue by specialty', $net, 'Net revenue')],
            ],
        ];
    }

    /**
     * @param array<int, array<string, mixed>> $matrix
     * @param array<int, array<string, mixed>> $totalRevenueRows
     * @param array<int, array<string, mixed>> $netRevenueRows
     * @return array<int, array<string, mixed>>
     */
    private function mergeExactLegacySpecialtyMetricsIntoMatrix(
        array $matrix,
        array $totalRevenueRows,
        array $netRevenueRows
    ): array {
        $totalRevenueMap = [];
        $netRevenueMap = [];

        foreach ($totalRevenueRows as $row) {
            $id = trim((string)($row['id'] ?? ''));

            if ($id !== '') {
                $totalRevenueMap[$id] = (float)($row['value'] ?? 0);
            }
        }

        foreach ($netRevenueRows as $row) {
            $id = trim((string)($row['id'] ?? ''));

            if ($id !== '') {
                $netRevenueMap[$id] = (float)($row['value'] ?? 0);
            }
        }

        foreach ($matrix as &$row) {
            $id = trim((string)($row['id'] ?? ''));

            $row['total_revenue_value'] = array_key_exists($id, $totalRevenueMap)
                ? $totalRevenueMap[$id]
                : null;

            $row['net_value'] = array_key_exists($id, $netRevenueMap)
                ? $netRevenueMap[$id]
                : null;
        }
        unset($row);

        return $matrix;
    }

    /** @return array<string,mixed> */
    private function card(string $title, float $current, float $compare, ChartDataService $chartService): array
    {
        return [
            'title' => $title,
            'current_total' => $current,
            'compare_total' => $compare,
            'percent' => $chartService->percentChange($current, $compare),
        ];
    }

    /** @param array<int,array<string,mixed>> $rows @return array<string,mixed> */
    private function payload(string $title, array $rows, string $seriesLabel): array
    {
        return [
            'title' => $title,
            'labels' => array_map(static function (array $row): string { return (string)($row['label'] ?? ''); }, $rows),
            'series' => [[
                'label' => $seriesLabel,
                'values' => array_map(static function (array $row): float { return (float)($row['value'] ?? 0); }, $rows),
            ]],
        ];
    }

    private function logError(string $label, Throwable $e): void
    {
        @file_put_contents(\base_path('storage/logs/app.log'), '[' . date('Y-m-d H:i:s') . '] ' . $label . ': ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
    }
}
