<?php

namespace App\Console\Commands;

//use App\Http\Controllers\Dashboard1Controller;
use App\Http\Controllers\DashboardController;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Http\Request;
use Throwable;

class GenerateDashboardCache extends Command
{
    protected $signature = 'dashboard:generate-cache
        {--target=clinic : clinic|main|both}
        {--mode=monthly : monthly|quarterly|yearly|all}
        {--month= : YYYY-MM for monthly}
        {--quarter= : YYYY-QN for quarterly}
        {--year= : YYYY for yearly}
        {--clinics=* : Limit clinics (defaults to all for target)}
        {--skip-all : Skip ALL aggregate for clinic dashboard}
        {--sleep=0 : Seconds to sleep between jobs}
        {--dry-run : Print jobs without running}';

    protected $description = 'Generate dashboard caches per clinic and period (monthly/quarterly/yearly)';

    public function handle()
    {
        $targets = $this->resolveTargets((string) $this->option('target'));
        if (empty($targets)) {
            $this->error('Invalid --target. Use clinic, main, or both.');
            return Command::FAILURE;
        }

        $modes = $this->resolveModes((string) $this->option('mode'));
        if (empty($modes)) {
            $this->error('Invalid --mode. Use monthly, quarterly, yearly, or all.');
            return Command::FAILURE;
        }

        $periods = $this->resolvePeriods($modes);
        if ($periods === null) {
            return Command::FAILURE;
        }

        $sleepSeconds = max((int) $this->option('sleep'), 0);
        $dryRun = (bool) $this->option('dry-run');

        $clinicFilter = (array) $this->option('clinics');
        $includeAll = in_array('clinic', $targets, true) && !$this->option('skip-all');
        if (!empty($clinicFilter) && $includeAll) {
            $this->warn('ALL aggregate uses caches from the full clinic list; run without --clinics for complete ALL results.');
        }

        foreach ($targets as $target) {
            $clinics = $this->resolveClinics($target, $clinicFilter);
            if (empty($clinics)) {
                $this->warn("No clinics matched for target '{$target}'.");
                continue;
            }

            $this->info(strtoupper($target) . ' dashboard cache generation');

            foreach ($modes as $mode) {
                $period = $periods[$mode] ?? null;
                if (!$period) {
                    continue;
                }
                $label = $period['label'];
                $this->line("Mode: {$mode} ({$label})");

                foreach ($clinics as $clinic) {
                    $this->line(" - Clinic {$clinic}");
                    if ($dryRun) {
                        continue;
                    }
                    $this->runJob($target, $mode, $period, $clinic, true);
                    if ($sleepSeconds > 0) {
                        sleep($sleepSeconds);
                    }
                }

                if ($target === 'clinic' && $includeAll) {
                    $this->line(' - Clinic ALL (aggregate)');
                    if (!$dryRun) {
                        $this->runJob($target, $mode, $period, 'ALL', false);
                        if ($sleepSeconds > 0) {
                            sleep($sleepSeconds);
                        }
                    }
                }
            }
        }

        $this->info('Dashboard cache generation complete.');

        return Command::SUCCESS;
    }

    private function resolveTargets(string $target): array
    {
        $target = strtolower(trim($target));
        if ($target === 'both') {
            return ['clinic', 'main'];
        }
        if (in_array($target, ['clinic', 'main'], true)) {
            return [$target];
        }
        return [];
    }

    private function resolveModes(string $mode): array
    {
        $mode = strtolower(trim($mode));
        if ($mode === 'all') {
            return ['monthly', 'quarterly', 'yearly'];
        }
        if (in_array($mode, ['monthly', 'quarterly', 'yearly'], true)) {
            return [$mode];
        }
        return [];
    }

    private function resolvePeriods(array $modes): ?array
    {
        $periods = [];
        $now = Carbon::today();

        if (in_array('monthly', $modes, true)) {
            $monthInput = $this->option('month');
            $monthDate = $this->parseMonth($monthInput ?: $now->format('Y-m'));
            if (!$monthDate) {
                $this->error('Invalid --month. Use YYYY-MM.');
                return null;
            }
            $periods['monthly'] = [
                'month' => $monthDate->format('Y-m'),
                'date' => $monthDate->format('Y-m-01'),
                'label' => $monthDate->format('F Y'),
            ];
        }

        if (in_array('quarterly', $modes, true)) {
            $quarterInput = $this->option('quarter');
            $quarter = $this->parseQuarter($quarterInput, $now);
            if (!$quarter) {
                $this->error('Invalid --quarter. Use YYYY-QN.');
                return null;
            }
            $periods['quarterly'] = [
                'quarter' => $quarter['key'],
                'date' => $quarter['start']->toDateString(),
                'label' => $quarter['label'],
            ];
        }

        if (in_array('yearly', $modes, true)) {
            $yearInput = $this->option('year');
            $year = $this->parseYear($yearInput, $now);
            if (!$year) {
                $this->error('Invalid --year. Use YYYY.');
                return null;
            }
            $periods['yearly'] = [
                'year' => $year,
                'date' => $year . '-01-01',
                'label' => (string) $year,
            ];
        }

        return $periods;
    }

    private function parseMonth(?string $month): ?Carbon
    {
        $month = $month ? trim($month) : null;
        if (!$month || !preg_match('/^\\d{4}-\\d{2}$/', $month)) {
            return null;
        }
        try {
            return Carbon::createFromFormat('Y-m', $month)->startOfMonth();
        } catch (Throwable $e) {
            return null;
        }
    }

    private function parseQuarter(?string $quarter, Carbon $fallback): ?array
    {
        $quarter = $quarter ? trim($quarter) : null;
        if ($quarter && preg_match('/^(\\d{4})-Q([1-4])$/', $quarter, $m)) {
            $year = (int) $m[1];
            $q = (int) $m[2];
        } else {
            $year = (int) $fallback->year;
            $q = (int) $fallback->quarter;
        }

        if ($q < 1 || $q > 4) {
            return null;
        }

        $startMonth = 1 + (($q - 1) * 3);
        $start = Carbon::create($year, $startMonth, 1)->startOfMonth();
        $label = sprintf('Q%d %d (%s–%s)', $q, $year, $start->format('M'), $start->copy()->addMonths(2)->format('M'));

        return [
            'key' => sprintf('%d-Q%d', $year, $q),
            'start' => $start,
            'label' => $label,
        ];
    }

    private function parseYear(?string $year, Carbon $fallback): ?int
    {
        $year = $year ? trim($year) : null;
        if (!$year) {
            return (int) $fallback->year;
        }
        if (!preg_match('/^\\d{4}$/', $year)) {
            return null;
        }
        return (int) $year;
    }

    private function resolveClinics(string $target, array $filter): array
    {
        $filter = array_filter(array_map('trim', $filter));
        $allowed = $target === 'clinic' ? $this->clinicDashboardClinics() : $this->mainDashboardClinics();

        if (empty($filter)) {
            return $allowed;
        }

        $filtered = array_values(array_filter($allowed, function ($clinic) use ($filter) {
            return in_array($clinic, $filter, true);
        }));

        $unknown = array_diff($filter, $allowed);
        if (!empty($unknown)) {
            $this->warn('Unknown clinics ignored: ' . implode(', ', $unknown));
        }

        return $filtered;
    }

    private function runJob(string $target, string $mode, array $period, string $clinic, bool $live): void
    {
        $params = [
            'clinic' => $clinic,
            'mode' => $mode,
            'date' => $period['date'] ?? Carbon::today()->toDateString(),
        ];

        if ($mode === 'monthly') {
            $params['month'] = $period['month'] ?? null;
        } elseif ($mode === 'quarterly') {
            $params['quarter'] = $period['quarter'] ?? null;
        } elseif ($mode === 'yearly') {
            $params['year'] = $period['year'] ?? null;
            $params['persist_yearly'] = 1;
        }

        if ($live) {
            $params['live'] = 1;
        }

        $path = $target === 'clinic' ? '/clinic_dashboard' : '/dashboard';
        $request = Request::create($path, 'GET', $params);

        try {
            if ($target === 'clinic') {
                app(DashboardController::class)->index($request);
            } 
        } catch (Throwable $e) {
            $this->error('   Failed: ' . $e->getMessage());
            report($e);
        }
    }

    private function clinicDashboardClinics(): array
    {
        return [
            'MAM_A',
            'MAM_B',
            'MAM_C1',
            'MAM_SPT',
            'MAM_SDG',
            'MAM_TL',
            'MAM_TBZY',
        ];
    }

    private function mainDashboardClinics(): array
    {
        return $this->clinicDashboardClinics();
    }
}
