<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Carbon\Carbon;

class DynamicReport extends Component
{
    public $filters = [
        'courses' => [],
        'levels' => [],
        'types' => [],
        'seasons' => [],
        'months' => [],
    ];

    public $filter_options = [
        'courses' => [],
        'levels' => [],
        'types' => [],
        'seasons' => [],
        'months' => [],
    ];

    public $chart = [
        'labels' => [],
        'datasets' => [],
    ];

    public function mount()
    {
        $this->resetReport();
        $this->initFiltersOptions();
    }

    public function resetReport()
    {
        $this->chart = [
            'labels' => [],
            'datasets' => []
        ];
    }

    public function initFiltersOptions()
    {
        // courses
        $this->filter_options['courses'] = \App\Models\Course::query()
            ->select('name')
            ->where('enabled', true)
            ->whereNull('deleted_at')
            ->groupBy('name')
            ->orderBy('name')
            ->pluck('name')
            ->values()
            ->toArray();

        // levels
        $this->filter_options['levels'] = \App\Models\CourseLevel::query()
            ->where('enabled', true)
            ->orderBy('name')
            ->get(['id', 'name'])
            ->toArray();

        // types
        $this->filter_options['types'] = \App\Models\CourseType::query()
            ->where('enabled', true)
            ->orderBy('name')
            ->get(['id', 'name'])
            ->toArray();

        // seasons
        $this->filter_options['seasons'] = $this->deriveSeasonOptionsFromCourseDateFrom();

        // months
        $this->filter_options['months'] = array_map(
            fn($m) => ['id' => $m, 'name' => $this->monthLabels()[$m]],
            $this->fiscalMonths()
        );
    }

    public function applyFilters()
    {
        $monthsToShow = $this->fiscalMonths();
        if (!empty($this->filters['months'])) {
            $selected = array_map('intval', $this->filters['months']);
            $monthsToShow = array_values(array_filter(
                $monthsToShow,
                fn($m) => in_array($m, $selected, true)
            ));
        }

        $labels = array_map(fn($m) => $this->monthLabels()[$m], $monthsToShow);

        $selectedSeasons = $this->filters['seasons'] ?? [];
        $selectedSeasons = array_values(array_filter($selectedSeasons));

        $rows = \App\Models\MemberCourse::query()
            ->join('courses', 'courses.id', '=', 'member_courses.course_id')
            ->leftJoin('course_levels', 'course_levels.id', '=', 'courses.course_level_id')
            ->leftJoin('course_types', 'course_types.id', '=', 'courses.course_type_id')
            ->whereNull('courses.deleted_at')
            ->where('courses.enabled', 1)
            ->when(!empty($this->filters['courses']), fn($q) => $q->whereIn('courses.name', $this->filters['courses']))
            ->when(!empty($this->filters['levels']), fn($q) => $q->whereIn('courses.course_level_id', $this->filters['levels']))
            ->when(!empty($this->filters['types']), fn($q) => $q->whereIn('courses.course_type_id', $this->filters['types']))
            ->select([
                'member_courses.id as member_course_id',
                'member_courses.member_id',
                'member_courses.months',
                'courses.id as course_id',
                'courses.name as course_name',
                'courses.date_from',
                'courses.date_to',
                'course_levels.name as level_name',
                'course_types.name as type_name',
            ])
            ->get();

        $bucket = [];
        foreach ($rows as $r) {
            $seasonLabel = $this->fiscalSeasonFromDates($r->date_from, $r->date_to);

            if (!empty($selectedSeasons)) {
                if (!$seasonLabel || !in_array($seasonLabel, $selectedSeasons, true)) {
                    continue;
                }
            }

            $activeMonths = $this->activeMonthsFromJson($r->months);
            if (empty($activeMonths)) continue;

            if (!empty($this->filters['months'])) {
                $activeMonths = array_values(array_intersect($activeMonths, array_map('intval', $this->filters['months'])));
                if (empty($activeMonths)) continue;
            }

            $seriesKey = $this->makeSeriesKey($r, $seasonLabel);

            foreach ($activeMonths as $m) {
                if (!in_array($m, $monthsToShow, true)) continue;
                $bucket[$seriesKey][$m][$r->member_course_id] = true;
            }
        }

        $datasets = [];
        foreach ($bucket as $seriesKey => $monthsMap) {
            $data = [];
            foreach ($monthsToShow as $m) {
                $data[] = isset($monthsMap[$m]) ? count($monthsMap[$m]) : 0;
            }
            $datasets[] = [
                'label' => $seriesKey,
                'data'  => $data,
            ];
        }

        $this->chart = [
            'labels'   => $labels,
            'datasets' => $datasets,
        ];

        $this->dispatchBrowserEvent('dynamic-report:updated', [
            'chart' => $this->chart,
        ]);
    }

    private function activeMonthsFromJson(?string $json)
    {
        if (!$json) return [];

        $decoded = json_decode($json, true);
        if (!is_array($decoded)) return [];

        $out = [];
        foreach ($decoded as $item) {
            $m = $item['m'] ?? null;
            $st = $item['status'] ?? null;

            if ($m === null) continue;
            $m = (int) $m;

            if ((int) $st !== 1) continue;

            if ($m >= 1 && $m <= 12) $out[] = $m;
        }

        $out = array_values(array_unique($out));
        sort($out);

        return $out;
    }

    private function fiscalSeasonFromDates(?string $dateFrom, ?string $dateTo): ?string
    {
        if (!$dateFrom) return null;

        $from = \Carbon\Carbon::parse($dateFrom);
        $to   = $dateTo ? \Carbon\Carbon::parse($dateTo) : null;

        // sicurezza: se date_to esiste ed è prima di date_from, ignoriamo date_to
        if ($to && $to->lessThan($from)) {
            $to = null;
        }

        /**
         * Strategia:
         * - la stagione è determinata dal "cuore" del corso
         * - se date_to esiste, prendiamo il punto medio
         * - altrimenti usiamo date_from
         */
        if ($to) {
            $midTimestamp = (int) (($from->timestamp + $to->timestamp) / 2);
            $ref = \Carbon\Carbon::createFromTimestamp($midTimestamp);
        } else {
            $ref = $from;
        }

        $startYear = ($ref->month >= 9) ? $ref->year : ($ref->year - 1);

        return $startYear . '-' . ($startYear + 1);
    }


    private function makeSeriesKey($r, ?string $seasonLabel): string
    {
        $parts = [];

        if (!empty($this->filters['courses'])) $parts[] = $r->course_name ?? '';
        if (!empty($this->filters['levels']))  $parts[] = $r->level_name ?? '';
        if (!empty($this->filters['types']))   $parts[] = $r->type_name ?? '';

        if (!empty($this->filters['seasons']) && $seasonLabel) $parts[] = $seasonLabel;

        if (empty(array_filter($parts))) {
            $parts[] = $r->course_name ?? 'Totale';
        }

        $parts = array_values(array_filter($parts, fn($p) => trim($p) !== ''));
        return implode(' - ', $parts);
    }

    private function deriveSeasonOptionsFromCourseDateFrom()
    {
        $dates = \App\Models\Course::query()
            ->where('enabled', 1)
            ->whereNull('deleted_at')
            ->whereNotNull('date_from')
            ->whereNotNull('date_to')
            ->pluck('date_to', 'date_from')
            ->all();

        $seasons = [];
        foreach ($dates as $d_from => $d_to) {
            $s = $this->fiscalSeasonFromDates($d_from, $d_to);
            if ($s) $seasons[$s] = true;
        }

        $out = array_keys($seasons);
        rsort($out);

        return $out;
    }

    private function fiscalMonths()
    {
        return [9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8];
    }

    private function monthLabels()
    {
        return [
            1 => 'Gen',
            2 => 'Feb',
            3 => 'Mar',
            4 => 'Apr',
            5 => 'Mag',
            6 => 'Giu',
            7 => 'Lug',
            8 => 'Ago',
            9 => 'Set',
            10 => 'Ott',
            11 => 'Nov',
            12 => 'Dic',
        ];
    }

    public function render()
    {
        return view('livewire.dynamic_report');
    }
}
