<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\Course;
use App\Models\MemberCard;
use App\Http\Middleware\TenantMiddleware;

class Reports extends Component
{
    public $type = 'anagrafica';
    public $seasonFilter;

    public $courses = [];
    public $selectedCourse = null;

    public function boot()
    {
        app(TenantMiddleware::class)->setupTenantConnection();

    }

    public function mount()
    {
        if (Auth::user()->level != env('LEVEL_ADMIN', 0))
            return redirect()->to('/reports');

        if (isset($_GET["type"]))
            $this->type = $_GET["type"];

        $this->seasonFilter = $this->getCurrentSeason();
        $this->courses = $this->getCoursesForSelect();
    }

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


    private function getCurrentSeason()
    {
        $now = Carbon::now();
        $currentYear = $now->year;
        if ($now->month >= 9) {
            return $currentYear . '-' . ($currentYear + 1);
        } else {
            return ($currentYear - 1) . '-' . $currentYear;
        }
    }

    public function getAvailableSeasons()
    {
        $seasons = [];
        $currentYear = Carbon::now()->year;
        $startYear = 2023;

        $endYear = Carbon::now()->month >= 9 ? $currentYear + 1 : $currentYear;

        for ($year = $startYear; $year < $endYear; $year++) {
            $seasons[] = $year . '-' . ($year + 1);
        }

        return array_reverse($seasons);
    }


    private function parseSeason($season)
    {
        $parts = explode('-', $season);
        return [
            'start_year' => (int)$parts[0],
            'end_year' => (int)$parts[1]
        ];
    }


    private function getSeasonDateRange($season)
    {
        $years = $this->parseSeason($season);

        return [
            'start' => Carbon::create($years['start_year'], 9, 1),
            'end' => Carbon::create($years['end_year'], 8, 31)
        ];
    }

    public function setSelectedCourse($courseId)
    {
        $this->selectedCourse = $courseId;
        Log::info('Selected course set to: ' . $courseId);
        return $this->getCourseMonthlyEarnings();
    }

    public function getTesseratiData()
    {
        $endYear = $this->parseSeason($this->seasonFilter)['end_year'];
        return self::getMemberCountChartData($endYear, 3);
    }

    public function change($type)
    {
        $this->type = $type;
    }

    public function updateCharts()
    {
        $this->courses = $this->getCoursesForSelect();
        $this->emit('chartsUpdated');
        $this->dispatchBrowserEvent('chartsUpdated');
    }

    public function updateCourseChart()
    {
        $this->emit('chartsUpdated');
        $this->dispatchBrowserEvent('chartsUpdated');
    }

    public function updatedSeasonFilter()
    {
        $this->courses = $this->getCoursesForSelect();
        $this->emit('chartsUpdated');
        $this->dispatchBrowserEvent('chartsUpdated');
    }

    public function setSeasonFilter($season)
    {
        $this->seasonFilter = $season;
    }

    protected function setupTenantConnection()
    {
        $user = auth()->user();

        config(['database.connections.tenant' => [
            'driver' => 'mysql',
            'host' => '127.0.0.1',
            'port' => '3306',
            'database' => $user->tenant_database,
            'username' => $user->tenant_username,
            'password' => $user->tenant_password,
        ]]);

        config(['database.default' => 'tenant']);
        DB::purge('tenant');
        DB::reconnect('tenant');
    }
    public function getMonthlyTotals()
    {
        Log::info('=== getMonthlyTotals called ===');
        Log::info('Current seasonFilter: ' . $this->seasonFilter);

        $dateRange = $this->getSeasonDateRange($this->seasonFilter);

        Log::info('Date range start: ' . $dateRange['start']);
        Log::info('Date range end: ' . $dateRange['end']);
        $monthOrder = [9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8];
        $monthNames = ['Set', 'Ott', 'Nov', 'Dic', 'Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago'];

        $incomeData = array_fill(0, 12, 0);
        $expenseData = array_fill(0, 12, 0);
        $this->setupTenantConnection();

        $incomeRecords = DB::table('records')
            ->join('records_rows', 'records.id', '=', 'records_rows.record_id')
            ->whereBetween('records.date', [$dateRange['start'], $dateRange['end']])
            ->where('records.type', 'IN')
            ->select(DB::raw('MONTH(records.date) as month_num'), DB::raw('SUM(records_rows.amount) as total'))
            ->groupBy('month_num')
            ->get();

        $expenseRecords = DB::table('records')
            ->join('records_rows', 'records.id', '=', 'records_rows.record_id')
            ->whereBetween('records.date', [$dateRange['start'], $dateRange['end']])
            ->where('records.type', 'OUT')
            ->select(DB::raw('MONTH(records.date) as month_num'), DB::raw('SUM(records_rows.amount) as total'))
            ->groupBy('month_num')
            ->get();

        foreach ($incomeRecords as $record) {
            $monthIndex = array_search($record->month_num, $monthOrder);
            if ($monthIndex !== false) {
                $incomeData[$monthIndex] = $record->total;
            }
        }

        foreach ($expenseRecords as $record) {
            $monthIndex = array_search($record->month_num, $monthOrder);
            if ($monthIndex !== false) {
                $expenseData[$monthIndex] = $record->total;
            }
        }

        Log::info('Income data: ' . json_encode($incomeData));
        Log::info('Expense data: ' . json_encode($expenseData));

        return [
            'labels' => $monthNames,
            'datasets' => [
                [
                    'label' => 'Entrate',
                    'data' => $incomeData,
                    'backgroundColor' => 'rgba(54, 162, 235, 0.5)'
                ],
                [
                    'label' => 'Uscite',
                    'data' => $expenseData,
                    'backgroundColor' => 'rgba(255, 99, 132, 0.5)'
                ],
            ]
        ];
    }

    public function getYearlySummary()
    {
        $dateRange = $this->getSeasonDateRange($this->seasonFilter);

        $totalIncome = DB::table('records')
            ->join('records_rows', 'records.id', '=', 'records_rows.record_id')
            ->whereBetween('records.date', [$dateRange['start'], $dateRange['end']])
            ->where('records.type', 'IN')
            ->sum('records_rows.amount');

        $totalExpenses = DB::table('records')
            ->join('records_rows', 'records.id', '=', 'records_rows.record_id')
            ->whereBetween('records.date', [$dateRange['start'], $dateRange['end']])
            ->where('records.type', 'OUT')
            ->sum('records_rows.amount');

        $delta = $totalIncome - $totalExpenses;

        return [
            'totalIncome' => $totalIncome,
            'totalExpenses' => $totalExpenses,
            'delta' => $delta
        ];
    }

    public function getTopCausalsByAmount($limit = 10)
    {
        $dateRange = $this->getSeasonDateRange($this->seasonFilter);

        $query = DB::table('records_rows')
            ->join('records', 'records_rows.record_id', '=', 'records.id')
            ->join('causals', 'records_rows.causal_id', '=', 'causals.id')
            ->leftJoin('courses', 'records_rows.course_id', '=', 'courses.id')
            ->leftJoin('subscriptions', 'records_rows.subscription_id', '=', 'subscriptions.id')
            ->whereBetween('records.date', [$dateRange['start'], $dateRange['end']]);

        $query->where('records.type', 'IN');

        Log::info('Query: ' . $query->toSql());

        $causals = $query->select(
            'causals.id',
            'causals.name',
            'causals.parent_id',
            'courses.id as course_id',
            'subscriptions.id as subscription_id',
            DB::raw('SUM(records_rows.amount) as total_amount')
        )
            ->where(function ($query) {
                $query->where('causals.no_reports', '=', '0')
                    ->orWhereNull('causals.no_reports');
            })
            ->groupBy('causals.id', 'causals.name', 'causals.parent_id', 'courses.id', 'subscriptions.id')
            ->orderBy('total_amount', 'desc')
            ->limit($limit)
            ->get();

        Log::info('Causals: ' . json_encode($causals));

        $inData = [];

        foreach ($causals as $causal) {
            $tempCausal = new \App\Models\Causal();
            $tempCausal->id = $causal->id;
            $tempCausal->name = $causal->name;
            $tempCausal->parent_id = $causal->parent_id;

            $treeName = $tempCausal->getTree();

            //$displayName = strlen($treeName) > 30 ? substr($treeName, 0, 27) . '...' : $treeName;
            $displayName = $treeName;

            if (isset($causal->course_id) && $causal->course_id) {
                $course = \App\Models\Course::find($causal->course_id);
                $displayName .= " - " . $course->getDetailsName();
            }
            if (isset($causal->subscription_id) && $causal->subscription_id) {
                $subscription = \App\Models\Subscription::find($causal->subscription_id);
                $displayName .= " - " . $subscription->name;
            }

            $inData[] = [
                'label' => $displayName,
                'value' => $causal->total_amount,
                'fullName' => $treeName
            ];
        }

        usort($inData, function ($a, $b) {
            return $b['value'] <=> $a['value'];
        });

        $inData = array_slice($inData, 0, $limit);

        return [
            'inLabels' => array_column($inData, 'label'),
            'inData' => $inData,
            'datasets' => [
                [
                    'label' => 'Entrate per Causale',
                    'data' => array_column($inData, 'value'),
                ]
            ]
        ];
    }

    public function getCoursesForSelect()
    {
        $seasonYears = $this->parseSeason($this->seasonFilter);

        Log::info('Getting courses for season: ' . $this->seasonFilter);
        Log::info('Season years: ' . json_encode($seasonYears));

        $courses = Course::with(['level', 'frequency'])
            ->where('active', true)
            ->where(function ($query) use ($seasonYears) {
                $query->where('year', $this->seasonFilter)
                    ->orWhere('year', 'like', '%' . $seasonYears['start_year'] . '-' . $seasonYears['end_year'] . '%')
                    ->orWhere('year', 'like', '%' . $seasonYears['start_year'] . '%')
                    ->orWhere('year', 'like', '%' . $seasonYears['end_year'] . '%');
            })
            ->orderBy('name')
            ->get()
            ->filter(function ($course) use ($seasonYears) {
                $courseYear = $course->year;

                if ($courseYear === $this->seasonFilter) {
                    return true;
                }

                if (
                    str_contains($courseYear, $seasonYears['start_year']) &&
                    str_contains($courseYear, $seasonYears['end_year'])
                ) {
                    return true;
                }

                if ($courseYear == $seasonYears['start_year'] || $courseYear == $seasonYears['end_year']) {
                    return true;
                }

                return false;
            })
            ->map(function ($course) {
                Log::info('Processing course: ' . $course->name . ' (ID: ' . $course->id . ')' . $course);

                $levelName = is_object($course->level) ? $course->level->name : 'No Level';
                $typeName = $course->getFormattedTypeField();
                $frequencyName = is_object($course->frequency) ? $course->frequency->name : 'No Frequency';
                $year = $course->year ?? '';

                return [
                    'id' => $course->id,
                    'name' => ($course->discipline?->name ? $course->discipline->name . ' - ' : '') . $course->name,
                    'full_name' => ($course->discipline?->name ? $course->discipline->name . ' - ' : '') . "{$course->name} - {$levelName} - {$typeName} - {$frequencyName} ({$year})",
                    'level_name' => $levelName,
                    'type_name' => $typeName,
                    'frequency_name' => $frequencyName,
                    'year' => $year
                ];
            })->sort(function($a, $b) {
                return strcmp($a['full_name'], $b['full_name']);
            })->values()->toArray();

        Log::info('Found ' . count($courses) . ' courses for season ' . $this->seasonFilter);

        return $courses;
    }

    public function getMonthlyTotalsForSeason($season)
    {
        $originalSeason = $this->seasonFilter;
        $this->seasonFilter = $season;

        $result = $this->getMonthlyTotals();

        $this->seasonFilter = $originalSeason;
        return $result;
    }


    public function getTopCausalsByAmountForSeason($season, $limit = 10)
    {
        $originalSeason = $this->seasonFilter;
        $this->seasonFilter = $season;

        $result = $this->getTopCausalsByAmount($limit);

        $this->seasonFilter = $originalSeason;
        return $result;
    }

    public function getTesseratiDataForSeason($season)
    {
        $originalSeason = $this->seasonFilter;
        $this->seasonFilter = $season;

        $result = $this->getTesseratiData();

        $this->seasonFilter = $originalSeason;
        return $result;
    }

    public function updatedSelectedCourse()
    {
        Log::info('updatedSelectedCourse called with: ' . $this->selectedCourse);
        if ($this->selectedCourse) {
            $this->emit('courseSelected', $this->selectedCourse);
            Log::info('Event emitted with course ID: ' . $this->selectedCourse);
        }
    }
    public function getCourseData($courseId)
    {
        $this->selectedCourse = $courseId;
        return $this->getCourseMonthlyEarnings($courseId);
    }
    public function getCourseMonthlyEarnings($courseId = null)
    {
        $courseId = $courseId ?? $this->selectedCourse;
        Log::info('Getting earnings for course ID: ' . $courseId);

        if (!$courseId) {
            return [
                'labels' => [],
                'datasets' => [],
                'tableData' => [],
                'isEmpty' => true,
                'message' => 'Seleziona un corso per visualizzare i dati'
            ];
        }

        $monthOrder = [9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8];
        $monthNames = [
            9 => 'Set',
            10 => 'Ott',
            11 => 'Nov',
            12 => 'Dic',
            1 => 'Gen',
            2 => 'Feb',
            3 => 'Mar',
            4 => 'Apr',
            5 => 'Mag',
            6 => 'Giu',
            7 => 'Lug',
            8 => 'Ago'
        ];
        $monthNamesExtended = [
            0 => 'Settembre',
            1 => 'Ottobre',
            2 => 'Novembre',
            3 => 'Dicembre',
            4 => 'Gennaio',
            5 => 'Febbraio',
            6 => 'Marzo',
            7 => 'Aprile',
            8 => 'Maggio',
            9 => 'Giugno',
            10 => 'Luglio',
            11 => 'Agosto'
        ];

        $monthlyData = [];
        foreach ($monthOrder as $i) {
            $monthlyData[$i] = [
                'earned' => 0,
                'total' => 0,
                'suspended' => 0,
                'participants' => 0
            ];
        }

        $rates = \App\Models\Rate::whereHas('member_course', function ($query) use ($courseId) {
            $query->where('course_id', $courseId);
        })->with('member_course')->get();

        if ($rates->isEmpty()) {
            return [
                'labels' => [],
                'datasets' => [],
                'tableData' => [],
                'isEmpty' => true,
                'message' => 'Nessun dato disponibile per questo corso nella stagione ' . $this->seasonFilter
            ];
        }

        $hasData = false;

        foreach ($rates as $rate) {
            $totalPrice = (float)($rate->price ?? 0);

            if ($rate->months) {
                $monthsData = json_decode($rate->months, true);

                if (is_array($monthsData) && count($monthsData) > 0) {
                    $pricePerMonth = $totalPrice / count($monthsData);

                    foreach ($monthsData as $month) {
                        $monthNumber = (int)$month;

                        if (isset($monthlyData[$monthNumber])) {
                            $monthlyData[$monthNumber]['total'] += $pricePerMonth;
                            $monthlyData[$monthNumber]['participants']++;
                            $hasData = true;

                            // if (!is_null($rate->record_id) && $rate->record_id !== '') {
                            //     $monthlyData[$monthNumber]['earned'] += $pricePerMonth;
                            // }

                            // pagamenti effettuati
                            if (!is_null($rate->record_id) && $rate->record_id !== '' && $rate->status == 1) {
                                $monthlyData[$monthNumber]['participants']--;
                                $monthlyData[$monthNumber]['earned'] += $pricePerMonth;
                            }
                            // pagamenti sospesi
                            if ($rate->status == 2) {
                                $monthlyData[$monthNumber]['participants']--;
                                $monthlyData[$monthNumber]['total'] -= $pricePerMonth;
                                $monthlyData[$monthNumber]['suspended']++;
                            }
                        }
                    }
                }
            }
        }

        if (!$hasData) {
            return [
                'labels' => [],
                'datasets' => [],
                'tableData' => [],
                'isEmpty' => true,
                'message' => 'Nessun pagamento registrato per questo corso nella stagione ' . $this->seasonFilter
            ];
        }

        $labels = [];
        $earnedData = [];
        $totalData = [];
        $participantData = [];
        $tableData = [];

        foreach ($monthOrder as $month) {
            $earned = round($monthlyData[$month]['earned'], 2);
            $total = round($monthlyData[$month]['total'], 2);
            $delta = max(0, $total - $earned);
            $participants = $monthlyData[$month]['participants'];
            $suspended = $monthlyData[$month]['suspended'];

            $labels[] = $monthNames[$month];
            $earnedData[] = $earned;
            $totalData[] = $total;
            $participantData[] = $participants;
            $suspendedData[] = $suspended;

            $percentage = $total > 0 ? round(($earned / $total) * 100, 1) : 0;

            $tableData[] = [
                'month' => $monthNames[$month],
                'participants' => $participants,
                'suspended' => $suspended,
                'earned' => $earned,
                'total' => $total,
                'delta' => $delta,
                'percentage' => $percentage
            ];
        }

        $daIncassareData = array_map(function($tot, $inc) {
            return $tot - $inc;
        }, $totalData, $earnedData);


        return [
            'labels' => $labels,
            'datasets' => [
                [
                    'label' => 'TOT. INCASSATO',
                    'data' => $earnedData,
                    'participantData' => $participantData,
                    'suspendedData' => $suspendedData,
                    'monthNamesExtended' => $monthNamesExtended,
                ],
                [
                    'label' => 'TOT. DA INCASSARE',
                    'data' => $daIncassareData,
                    'participantData' => $participantData,
                    'suspendedData' => $suspendedData,
                    'monthNamesExtended' => $monthNamesExtended,
                ]
            ],
            'tableData' => $tableData,
            'isEmpty' => false
        ];
    }

    public static function getMemberCountChartData($endYear = null, $span = 5)
    {
        if ($endYear === null) {
            $endYear = date('Y');
        }

        $startYear = $endYear - $span + 1;

        $memberCards = MemberCard::select('member_id', 'expire_date', 'card_id')
            ->with('card:id,name')
            ->whereNotNull('expire_date')
            ->whereNotNull('member_id')
            ->whereNotNull('card_id')
            ->where('status', '!=', 'cancelled')
            ->whereRaw('YEAR(expire_date) >= ?', [$startYear])
            ->whereRaw('YEAR(expire_date) <= ?', [$endYear])
            ->get();

        $cardTypes = $memberCards->pluck('card.name')->unique()->filter()->sort()->values();

        $seasonCounts = [];
        $seasonCardCounts = [];

        for ($year = $startYear; $year <= $endYear; $year++) {
            $seasonPeriod = ($year - 1) . '-' . $year;
            $seasonCounts[$seasonPeriod] = [];
            $seasonCardCounts[$seasonPeriod] = [];

            foreach ($cardTypes as $cardType) {
                $seasonCardCounts[$seasonPeriod][$cardType] = [];
            }
        }

        foreach ($memberCards as $card) {
            $expireYear = date('Y', strtotime($card->expire_date));
            $expireMonth = date('n', strtotime($card->expire_date));

            if ($expireMonth >= 9) {
                $seasonPeriod = $expireYear . '-' . ($expireYear + 1);
            } else {
                $seasonPeriod = ($expireYear - 1) . '-' . $expireYear;
            }

            if (isset($seasonCounts[$seasonPeriod])) {
                $seasonCounts[$seasonPeriod][$card->member_id] = true;

                $cardTypeName = $card->card->name ?? 'Unknown';
                if (isset($seasonCardCounts[$seasonPeriod][$cardTypeName])) {
                    $seasonCardCounts[$seasonPeriod][$cardTypeName][$card->member_id] = true;
                }
            }
        }

        $seasonLabels = [];
        $memberCountData = [];
        $cardTypeDatasets = [];

        $colors = [
            'rgba(255, 99, 132, 0.2)',
            'rgba(54, 162, 235, 0.2)',
            'rgba(255, 205, 86, 0.2)',
            'rgba(75, 192, 192, 0.2)',
            'rgba(153, 102, 255, 0.2)',
            'rgba(255, 159, 64, 0.2)',
            'rgba(199, 199, 199, 0.2)',
            'rgba(83, 102, 255, 0.2)',
        ];

        $borderColors = [
            'rgba(255, 99, 132, 1)',
            'rgba(54, 162, 235, 1)',
            'rgba(255, 205, 86, 1)',
            'rgba(75, 192, 192, 1)',
            'rgba(153, 102, 255, 1)',
            'rgba(255, 159, 64, 1)',
            'rgba(199, 199, 199, 1)',
            'rgba(83, 102, 255, 1)',
        ];

        foreach ($cardTypes as $index => $cardType) {
            $cardTypeDatasets[$cardType] = [
                'label' => $cardType,
                'data' => [],
                'backgroundColor' => $colors[$index % count($colors)],
                'borderColor' => $borderColors[$index % count($borderColors)],
                'borderWidth' => 2,
                'pointBackgroundColor' => $borderColors[$index % count($borderColors)],
                'pointRadius' => 4,
                'tension' => 0.3,
                'fill' => true
            ];
        }

        foreach ($seasonCounts as $seasonPeriod => $members) {
            $seasonLabels[] = $seasonPeriod;
            $memberCountData[] = count($members);

            foreach ($cardTypes as $cardType) {
                $cardTypeCount = isset($seasonCardCounts[$seasonPeriod][$cardType])
                    ? count($seasonCardCounts[$seasonPeriod][$cardType])
                    : 0;
                $cardTypeDatasets[$cardType]['data'][] = $cardTypeCount;
            }
        }

        $datasets = [
            [
                'label' => 'Totale Membri Tesserati',
                'data' => $memberCountData,
                'backgroundColor' => 'rgba(54, 162, 235, 0.2)',
                'borderColor' => 'rgba(54, 162, 235, 1)',
                'borderWidth' => 3,
                'pointBackgroundColor' => 'rgba(54, 162, 235, 1)',
                'pointRadius' => 6,
                'tension' => 0.3,
                'fill' => true,
                'type' => 'line'
            ]
        ];
        foreach ($cardTypeDatasets as $dataset) {
            $datasets[] = $dataset;
        }

        return [
            'labels' => $seasonLabels,
            'datasets' => $datasets
        ];
    }
}
