<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\AccessControl;
use App\Core\Auth;
use App\Core\Request;
use App\Core\View;
use App\Repositories\DiarCommandCenterRepository;
use DateTimeImmutable;
use Throwable;

final class DiarCommandCenterController
{
    public function index(): void
    {
        Auth::requireLogin();
        $this->requirePermission('diar.command.view');
        $overview = ['summary' => [], 'sites' => [], 'pipeline' => []];
        $loadError = '';
        try {
            $overview = (new DiarCommandCenterRepository())->overview($this->allowedSites());
        } catch (Throwable $e) {
            $loadError = $this->tr(
                'The DIAR operational overview is temporarily unavailable.',
                'تعذر تحميل النظرة التشغيلية لمنظومة مخاطر الأدوية مؤقتًا.'
            );
            $this->log($e, 'Index');
        }

        View::render('diar_command_center/index', [
            'title' => $this->tr('Medication Movement Intelligence', 'ذكاء حركات مخزون الأدوية'),
            'activePage' => 'diar-command-center',
            'hospitalCode' => Auth::hospital(),
            'hospital' => \config('hospitals.' . Auth::hospital(), []),
            'overview' => $overview,
            'loadError' => $loadError,
            'allowedSites' => $this->allowedSites(),
            'capabilities' => $this->capabilities(),
        ]);
    }

    public function runs(): void
    {
        Auth::requireLogin();
        $this->requirePermission('diar.engine_runs.view');
        $filters = [
            'site' => strtoupper(trim((string)Request::get('site', ''))),
            'status' => strtoupper(trim((string)Request::get('status', ''))),
            'run_type' => strtoupper(trim((string)Request::get('run_type', ''))),
            'q' => trim((string)Request::get('q', '')),
        ];
        $page = max(1, (int)Request::get('p', '1'));
        $perPage = max(20, min(100, (int)Request::get('per_page', '50')));
        $data = ['rows' => [], 'total' => 0, 'page' => $page, 'per_page' => $perPage];
        $loadError = '';
        try {
            $data = (new DiarCommandCenterRepository())->runs($filters, $this->allowedSites(), $page, $perPage);
        } catch (Throwable $e) {
            $loadError = $this->tr('Engine runs could not be loaded.', 'تعذر تحميل سجل تشغيلات المحرك.');
            $this->log($e, 'Runs');
        }

        View::render('diar_command_center/runs', [
            'title' => $this->tr('DIAR Engine Runs', 'تشغيلات محرك مخاطر الأدوية'),
            'activePage' => 'diar-engine-runs',
            'hospitalCode' => Auth::hospital(),
            'hospital' => \config('hospitals.' . Auth::hospital(), []),
            'runData' => $data,
            'filters' => $filters,
            'loadError' => $loadError,
            'allowedSites' => $this->allowedSites(),
            'capabilities' => $this->capabilities(),
        ]);
    }

    public function movements(): void
    {
        Auth::requireLogin();
        $this->requirePermission('diar.movement_dictionary.view');
        $filters = [
            'site' => strtoupper(trim((string)Request::get('site', $this->defaultSite()))),
            'q' => trim((string)Request::get('q', '')),
            'effect' => trim((string)Request::get('effect', '')),
            'mapping_status' => strtoupper(trim((string)Request::get('mapping_status', ''))),
        ];
        $page = max(1, (int)Request::get('p', '1'));
        $perPage = max(20, min(100, (int)Request::get('per_page', '50')));
        $data = ['site' => $filters['site'], 'version' => [], 'rows' => [], 'total' => 0, 'page' => $page, 'per_page' => $perPage];
        $loadError = '';
        try {
            $data = (new DiarCommandCenterRepository())->movementDictionary($filters, $this->allowedSites(), $page, $perPage);
        } catch (Throwable $e) {
            $loadError = $this->tr('The movement dictionary could not be loaded.', 'تعذر تحميل قاموس أنواع الحركات.');
            $this->log($e, 'Movements');
        }

        View::render('diar_command_center/movements', [
            'title' => $this->tr('Movement Dictionary', 'قاموس أنواع الحركات'),
            'activePage' => 'diar-movement-dictionary',
            'hospitalCode' => Auth::hospital(),
            'hospital' => \config('hospitals.' . Auth::hospital(), []),
            'movementData' => $data,
            'filters' => $filters,
            'loadError' => $loadError,
            'allowedSites' => $this->allowedSites(),
            'capabilities' => $this->capabilities(),
        ]);
    }

    public function facts(): void
    {
        Auth::requireLogin();
        $this->requirePermission('diar.daily_fact.view');
        $today = new DateTimeImmutable('today');
        $defaultTo = $today->modify('-1 day');
        $defaultFrom = $defaultTo->modify('-6 days');
        $dateFrom = $this->validDate((string)Request::get('date_from', $defaultFrom->format('Y-m-d')), $defaultFrom);
        $dateTo = $this->validDate((string)Request::get('date_to', $defaultTo->format('Y-m-d')), $defaultTo);
        if ($dateFrom > $dateTo) {
            $dateFrom = $dateTo;
        }
        if ((int)$dateFrom->diff($dateTo)->format('%a') > 30) {
            $dateFrom = $dateTo->modify('-30 days');
        }

        $filters = [
            'site' => strtoupper(trim((string)Request::get('site', $this->defaultSite()))),
            'date_from' => $dateFrom->format('Y-m-d'),
            'date_to' => $dateTo->format('Y-m-d'),
            'branch' => trim((string)Request::get('branch', '')),
            'store' => trim((string)Request::get('store', '')),
            'item' => trim((string)Request::get('item', '')),
            'unit' => trim((string)Request::get('unit', '')),
            'transcode' => trim((string)Request::get('transcode', '')),
            'effect' => trim((string)Request::get('effect', '')),
        ];
        $page = max(1, (int)Request::get('p', '1'));
        $perPage = max(20, min(100, (int)Request::get('per_page', '50')));
        $data = [
            'site' => $filters['site'], 'rows' => [], 'summary' => [], 'total' => 0,
            'page' => $page, 'per_page' => $perPage, 'filters' => $filters, 'options' => [],
        ];
        $loadError = '';
        try {
            $data = (new DiarCommandCenterRepository())->dailyFacts($filters, $this->allowedSites(), $page, $perPage);
        } catch (Throwable $e) {
            $loadError = $this->tr('Daily movement facts could not be loaded.', 'تعذر تحميل بيانات الحركات اليومية المجمعة.');
            $this->log($e, 'Facts');
        }

        View::render('diar_command_center/facts', [
            'title' => $this->tr('Medication Daily Facts', 'الحقائق اليومية لحركات الأدوية'),
            'activePage' => 'diar-daily-facts',
            'hospitalCode' => Auth::hospital(),
            'hospital' => \config('hospitals.' . Auth::hospital(), []),
            'factData' => $data,
            'filters' => $filters,
            'loadError' => $loadError,
            'allowedSites' => $this->allowedSites(),
            'capabilities' => $this->capabilities(),
        ]);
    }


    public function profiles(): void
    {
        Auth::requireLogin();
        $this->requirePermission('diar.command.view');
        $filters = [
            'site' => strtoupper(trim((string)Request::get('site', $this->defaultSite()))),
            'readiness' => strtoupper(trim((string)Request::get('readiness', ''))),
            'q' => trim((string)Request::get('q', '')),
            'branch' => trim((string)Request::get('branch', '')),
            'store' => trim((string)Request::get('store', '')),
            'item' => trim((string)Request::get('item', '')),
            'unit' => trim((string)Request::get('unit', '')),
            'transcode' => trim((string)Request::get('transcode', '')),
            'effect' => trim((string)Request::get('effect', '')),
        ];
        $page = max(1, (int)Request::get('p', '1'));
        $perPage = max(20, min(100, (int)Request::get('per_page', '50')));
        $data = [
            'site' => $filters['site'],
            'availability' => ['status' => 'PENDING_5D', 'missing_columns' => []],
            'summary' => [], 'rows' => [], 'total' => 0, 'page' => $page, 'per_page' => $perPage,
            'filters' => $filters, 'options' => [],
        ];
        $loadError = '';
        try {
            $data = (new DiarCommandCenterRepository())->statisticalProfiles(
                $filters,
                $this->allowedSites(),
                $page,
                $perPage
            );
        } catch (Throwable $e) {
            $loadError = $this->tr(
                'Statistical profiles could not be loaded.',
                'تعذر تحميل الملفات الإحصائية.'
            );
            $this->log($e, 'Profiles');
        }

        View::render('diar_command_center/profiles', [
            'title' => $this->tr('Statistical Baselines', 'الخطوط الإحصائية'),
            'activePage' => 'diar-statistical-profiles',
            'hospitalCode' => Auth::hospital(),
            'hospital' => \config('hospitals.' . Auth::hospital(), []),
            'profileData' => $data,
            'filters' => $filters,
            'loadError' => $loadError,
            'allowedSites' => $this->allowedSites(),
            'capabilities' => $this->capabilities(),
        ]);
    }

    public function candidates(): void
    {
        Auth::requireLogin();
        $this->requirePermission('diar.command.view');
        $requestedSite = strtoupper(trim((string)Request::get('site', '')));
        $data = [
            'status' => 'PENDING_DIAR_5E_R1',
            'sites' => [],
            'contract' => [],
        ];
        $loadError = '';
        try {
            $data = (new DiarCommandCenterRepository())->anomalyWorkspaceStatus(
                $this->allowedSites(),
                $requestedSite
            );
        } catch (Throwable $e) {
            $loadError = $this->tr(
                'The anomaly candidate workspace status could not be loaded.',
                'تعذر تحميل حالة مساحة مرشحي الحالات غير المعتادة.'
            );
            $this->log($e, 'Candidates');
        }

        View::render('diar_command_center/candidates', [
            'title' => $this->tr('Detected Deviations', 'الانحرافات المكتشفة'),
            'activePage' => 'diar-anomaly-candidates',
            'hospitalCode' => Auth::hospital(),
            'hospital' => \config('hospitals.' . Auth::hospital(), []),
            'candidateData' => $data,
            'requestedSite' => $requestedSite,
            'loadError' => $loadError,
            'allowedSites' => $this->allowedSites(),
            'capabilities' => $this->capabilities(),
        ]);
    }

    /** @return array<int,string> */
    private function allowedSites(): array
    {
        $sites = [];
        if (AccessControl::allowsBranch('njch')) {
            $sites[] = 'NJCH';
        }
        if (AccessControl::allowsBranch('mnh')) {
            $sites[] = 'MNH';
        }
        return $sites;
    }

    private function defaultSite(): string
    {
        $hospital = strtoupper((string)Auth::hospital());
        $sites = $this->allowedSites();
        return in_array($hospital, $sites, true) ? $hospital : (string)($sites[0] ?? 'NJCH');
    }

    /** @return array<string,bool> */
    private function capabilities(): array
    {
        return [
            'command' => AccessControl::allows('diar.command.view'),
            'runs' => AccessControl::allows('diar.engine_runs.view'),
            'movements' => AccessControl::allows('diar.movement_dictionary.view'),
            'facts' => AccessControl::allows('diar.daily_fact.view'),
            'profiles' => AccessControl::allows('diar.command.view'),
            'candidates' => AccessControl::allows('diar.command.view'),
            'investigations' => AccessControl::allows('diar.investigation.view'),
            'rules' => AccessControl::allows('diar.rules.view'),
        ];
    }

    private function requirePermission(string $permission): void
    {
        if (!AccessControl::allows($permission)) {
            AccessControl::forbidden();
        }
    }

    private function validDate(string $value, DateTimeImmutable $fallback): DateTimeImmutable
    {
        $date = DateTimeImmutable::createFromFormat('!Y-m-d', trim($value));
        return $date instanceof DateTimeImmutable ? $date : $fallback;
    }

    private function tr(string $en, string $ar): string
    {
        return current_lang() === 'ar' ? $ar : $en;
    }

    private function log(Throwable $e, string $context): void
    {
        error_log('[DIAR-UI-4-R1][' . $context . '] ' . $e->getMessage());
    }
}
