<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\AccessControl;
use App\Core\Auth;
use App\Core\BranchReadiness;
use App\Core\Request;
use App\Core\RequestTrace;
use App\Core\View;
use App\Repositories\RevenueRepository;
use App\Services\ChartDataService;
use App\Services\FairYearComparisonPolicy;
use DateTimeImmutable;

final class RevenueController
{
    public function index(): void
    {
        RequestTrace::begin('auth_session');
        Auth::requireLogin();
        RequestTrace::end('auth_session');

        if (!AccessControl::allows('revenue.view')) {
            http_response_code(403);
            View::render('errors/403', [
                'title' => current_lang() === 'ar' ? 'غير مصرح بالدخول' : 'Access not available',
                'activePage' => '',
            ]);
            return;
        }

        $currentYear = (int)date('Y');
        $mode = strtolower(trim((string)Request::get('mode', 'year')));
        if (!in_array($mode, ['year', 'range'], true)) {
            $mode = 'year';
        }

        $year = \safe_int(Request::get('year'), $currentYear);
        $compareYear = \safe_int(Request::get('compare_year'), $year - 1);
        $year = max(2014, min($currentYear, $year));
        $compareYear = max(2014, min($currentYear, $compareYear));
        $fromDate = $this->normalizeDate((string)Request::get('from_date', ''));
        $toDate = $this->normalizeDate((string)Request::get('to_date', ''));
        $filterError = '';
        if ($year === $compareYear) {
            $compareYear = $year > 2014 ? $year - 1 : min($currentYear, $year + 1);
            $filterError = current_lang() === 'ar'
                ? 'يجب اختيار سنتين مختلفتين للمقارنة. تم اختيار أقرب سنة متاحة تلقائيًا.'
                : 'Choose two different years for comparison. The nearest available year was selected automatically.';
        }

        if ($mode === 'range') {
            if ($fromDate === null) {
                $fromDate = sprintf('%04d-01-01', $year);
            }
            if ($toDate === null) {
                $toDate = sprintf('%04d-12-31', $year);
            }

            $from = new DateTimeImmutable($fromDate);
            $to = new DateTimeImmutable($toDate);
            if ($from > $to) {
                $filterError = current_lang() === 'ar'
                    ? 'يجب أن يكون تاريخ البداية قبل تاريخ النهاية.'
                    : 'From date must be on or before To date.';
                $toDate = $fromDate;
                $to = $from;
            }
            if ($from->format('Y') !== $to->format('Y')) {
                $filterError = current_lang() === 'ar'
                    ? 'يجب اختيار تاريخ البداية والنهاية داخل نفس السنة، كما في النظام السابق.'
                    : 'For clear comparison, start and end dates must be within the same calendar year.';
                $toDate = $from->format('Y') . '-12-31';
                $to = new DateTimeImmutable($toDate);
            }
            $year = (int)$from->format('Y');
            if ($compareYear === $year) {
                $compareYear = $year - 1;
            }
        } else {
            $fromDate = null;
            $toDate = null;
        }

        $comparisonPolicy = new FairYearComparisonPolicy();
        $comparisonContract = $comparisonPolicy->resolve($year, $compareYear);
        $availableYears = $comparisonPolicy->availableYears(2014);

        $queryFromDate = $fromDate;
        $queryToDate = $toDate;
        if ($mode === 'year' && !empty($comparisonContract['fair_current_year_comparison'])) {
            $queryFromDate = $comparisonContract['from_date'];
            $queryToDate = $comparisonContract['to_date'];
        }

        $requestedHospital = \normalize_hospital_code((string)Request::get('hospital', Auth::hospital()));
        $hospitalCode = $requestedHospital;
        if (!BranchReadiness::isLive($hospitalCode)) {
            $hospitalCode = Auth::hospital();
            $branchMessage = current_lang() === 'ar'
                ? 'الفرع المطلوب غير متاح حاليًا؛ تم الإبقاء على الفرع المعتمد الحالي.'
                : 'The requested branch is not currently available; the active approved branch was retained.';
            $filterError = trim($filterError . ' ' . $branchMessage);
        }

        $hospital = \config('hospitals.' . $hospitalCode);
        RequestTrace::context('hospital', $hospitalCode);
        RequestTrace::context('comparison', $year . '_vs_' . $compareYear);
        $repo = new RevenueRepository($hospitalCode);
        $chartService = new ChartDataService();

        $hasComparableCompletedMonths = !(
            $mode === 'year'
            && !empty($comparisonContract['fair_current_year_comparison'])
            && (int)$comparisonContract['last_complete_month'] < 1
        );

        if ($hasComparableCompletedMonths) {
            RequestTrace::begin('revenue_query');
            $revenueBundle = $repo->monthlyRevenueBundle(
                $year,
                $compareYear,
                (string)$hospital['moh_customer_code'],
                $queryFromDate,
                $queryToDate
            );
            RequestTrace::end('revenue_query');
            $totalRows = $revenueBundle['total'];
            $cashRows = $revenueBundle['cash'];
            $insuranceRows = $revenueBundle['insurance'];
            $mohRows = $revenueBundle['moh'];
            $revenueDataSource = $repo->lastRevenueSource();
            $revenueSummaryStatus = $repo->lastSummaryStatus();
            RequestTrace::begin('profit_loss_query');
            $profitLossRows = $repo->monthlyProfitLoss($year, $compareYear, (int)$hospital['profit_loss_company_id'], $queryFromDate, $queryToDate);
            RequestTrace::end('profit_loss_query');
        } else {
            $totalRows = $cashRows = $insuranceRows = $mohRows = $profitLossRows = [];
            $revenueDataSource = 'no_completed_months';
            $revenueSummaryStatus = [];
        }

        $visibleStartMonth = 1;
        $visibleEndMonth = 12;
        if ($mode === 'year' && !empty($comparisonContract['fair_current_year_comparison'])) {
            $visibleEndMonth = (int)$comparisonContract['last_complete_month'];
        } elseif ($mode === 'range' && $fromDate !== null && $toDate !== null) {
            $visibleStartMonth = (int)(new DateTimeImmutable($fromDate))->format('n');
            $visibleEndMonth = (int)(new DateTimeImmutable($toDate))->format('n');
        }

        $totalRows = $this->filterRowsByMonth($totalRows, $visibleStartMonth, $visibleEndMonth);
        $cashRows = $this->filterRowsByMonth($cashRows, $visibleStartMonth, $visibleEndMonth);
        $insuranceRows = $this->filterRowsByMonth($insuranceRows, $visibleStartMonth, $visibleEndMonth);
        $mohRows = $this->filterRowsByMonth($mohRows, $visibleStartMonth, $visibleEndMonth);
        $profitLossRows = $this->filterRowsByMonth($profitLossRows, $visibleStartMonth, $visibleEndMonth);

        RequestTrace::begin('payload_preparation');
        $charts = [
            'total' => [
                'title' => 'Monthly Total Revenue',
                'rows' => $totalRows,
                'payload' => $chartService->comparePayload($totalRows, 'Monthly Total Revenue', $year, $compareYear),
            ],
            'cash' => [
                'title' => 'Monthly Total Cash Revenue',
                'rows' => $cashRows,
                'payload' => $chartService->comparePayload($cashRows, 'Monthly Total Cash Revenue', $year, $compareYear),
            ],
            'insurance' => [
                'title' => 'Monthly Total Insurance Revenue',
                'rows' => $insuranceRows,
                'payload' => $chartService->comparePayload($insuranceRows, 'Monthly Total Insurance Revenue', $year, $compareYear),
            ],
            'moh' => [
                'title' => 'Monthly Total MOH Revenue',
                'rows' => $mohRows,
                'payload' => $chartService->comparePayload($mohRows, 'Monthly Total MOH Revenue', $year, $compareYear),
            ],
            'profit_loss' => [
                'title' => 'Monthly Total Profit / Loss',
                'rows' => $profitLossRows,
                'payload' => $chartService->comparePayload($profitLossRows, 'Monthly Total Profit / Loss', $year, $compareYear),
            ],
        ];

        $cards = [];
        foreach ($charts as $key => $chart) {
            $currentTotal = $chartService->total($chart['rows'], 'current_value');
            $compareTotal = $chartService->total($chart['rows'], 'compare_value');
            $cards[$key] = [
                'title' => $chart['title'],
                'current_total' => $currentTotal,
                'compare_total' => $compareTotal,
                'percent' => $chartService->percentChange($currentTotal, $compareTotal),
            ];
        }

        $compareFromDate = $fromDate !== null ? RevenueRepository::shiftDateToYear($fromDate, $compareYear) : null;
        $compareToDate = $toDate !== null ? RevenueRepository::shiftDateToYear($toDate, $compareYear) : null;

        RequestTrace::end('payload_preparation');
        View::render('revenue/index', [
            'title' => current_lang() === 'ar' ? 'الإيرادات والوضع المالي' : 'Revenue & Financial Position',
            'activePage' => 'revenue',
            'mode' => $mode,
            'year' => $year,
            'compareYear' => $compareYear,
            'fromDate' => $fromDate,
            'toDate' => $toDate,
            'compareFromDate' => $compareFromDate,
            'compareToDate' => $compareToDate,
            'filterError' => $filterError,
            'availableYears' => $availableYears,
            'comparisonContract' => $comparisonContract,
            'queryFromDate' => $queryFromDate,
            'queryToDate' => $queryToDate,
            'hospitalCode' => $hospitalCode,
            'hospital' => $hospital,
            'hospitals' => BranchReadiness::liveHospitals(\config('hospitals', [])),
            'charts' => $charts,
            'cards' => $cards,
            'revenueDataSource' => $revenueDataSource ?? 'batch',
            'revenueSummaryStatus' => $revenueSummaryStatus ?? [],
        ]);
    }

    public function performanceBeacon(): void
    {
        Auth::requireLogin();
        if (Request::method() !== 'POST') {
            http_response_code(405);
            header('Content-Type: application/json');
            echo json_encode(['ok'=>false, 'error'=>'POST required']);
            return;
        }
        $raw = file_get_contents('php://input');
        $payload = json_decode((string)$raw, true);
        if (!is_array($payload) || ($payload['schema'] ?? '') !== 'DDB_REVENUE_BROWSER_TRACE_V1') {
            http_response_code(422);
            header('Content-Type: application/json');
            echo json_encode(['ok'=>false, 'error'=>'Invalid trace payload']);
            return;
        }
        $file = RequestTrace::saveBrowserPayload($payload);
        header('Content-Type: application/json');
        echo json_encode(['ok'=>true, 'file'=>basename($file)]);
    }

    /** @param array<int, array<string, mixed>> $rows
     *  @return array<int, array<string, mixed>>
     */
    private function filterRowsByMonth(array $rows, int $startMonth, int $endMonth): array
    {
        if ($endMonth < $startMonth || $endMonth < 1) {
            return [];
        }
        return array_values(array_filter($rows, static function (array $row) use ($startMonth, $endMonth): bool {
            $month = (int)($row['code'] ?? 0);
            return $month >= $startMonth && $month <= $endMonth;
        }));
    }

    private function normalizeDate(string $value): ?string
    {
        $value = trim($value);
        if ($value === '') {
            return null;
        }
        $date = DateTimeImmutable::createFromFormat('!Y-m-d', $value);
        $errors = DateTimeImmutable::getLastErrors();
        if ($date === false) {
            return null;
        }
        if (is_array($errors) && ((int)($errors['warning_count'] ?? 0) > 0 || (int)($errors['error_count'] ?? 0) > 0)) {
            return null;
        }
        return $date->format('Y-m-d');
    }
}
