<?php

namespace App\Filament\Widgets;

use App\Models\Subscription;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Facades\DB;

class ChurnAnalysis extends ChartWidget
{
    protected static ?int $sort = 3;

    protected int|string|array $columnSpan = 'full';

    public function getHeading(): string
    {
        return 'Churn Analysis';
    }

    protected function getData(): array
    {
        $monthlyChurn = $this->getMonthlyChurnRate();
        $churnByProvider = $this->getChurnByProvider();
        $churnByPlan = $this->getChurnByPlan();

        return [
            'datasets' => [
                [
                    'label' => 'Monthly Churn Rate (%)',
                    'data' => array_values($monthlyChurn),
                    'borderColor' => 'rgba(239, 68, 68, 1)',
                    'backgroundColor' => 'rgba(239, 68, 68, 0.1)',
                    'fill' => true,
                    'tension' => 0.4,
                ],
            ],
            'labels' => array_keys($monthlyChurn),
        ];
    }

    protected function getType(): string
    {
        return 'line';
    }

    protected function getOptions(): array
    {
        return [
            'responsive' => true,
            'plugins' => [
                'legend' => [
                    'position' => 'top',
                ],
                'tooltip' => [
                    'callbacks' => [
                        'label' => 'function(context) {
                            let label = context.dataset.label || "";
                            if (label) {
                                label += ": ";
                            }
                            if (context.parsed.y !== null) {
                                label += context.parsed.y.toFixed(1) + "%";
                            }
                            return label;
                        }',
                    ],
                ],
            ],
            'scales' => [
                'y' => [
                    'beginAtZero' => true,
                    'max' => 20,
                    'ticks' => [
                        'callback' => 'function(value) {
                            return value + "%";
                        }',
                    ],
                ],
            ],
        ];
    }

    private function getMonthlyChurnRate(): array
    {
        $churnData = [];

        for ($i = 5; $i >= 0; $i--) {
            $month = now()->subMonths($i);
            $monthStart = $month->copy()->startOfMonth();
            $monthEnd = $month->copy()->endOfMonth();

            // Active subscriptions at the beginning of the month
            $activeAtStart = Subscription::query()
                ->where('status', 'active')
                ->where('created_at', '<', $monthStart)
                ->count();

            // Subscriptions cancelled during the month
            $cancelledDuringMonth = Subscription::query()
                ->where('status', 'cancelled')
                ->whereBetween('cancelled_at', [$monthStart, $monthEnd])
                ->count();

            // Calculate churn rate
            $churnRate = $activeAtStart > 0 ? ($cancelledDuringMonth / $activeAtStart) * 100 : 0;

            $churnData[$month->format('M Y')] = round($churnRate, 2);
        }

        return $churnData;
    }

    private function getChurnByProvider(): array
    {
        $castExpression = $this->getCastExpression();

        return Subscription::query()
            ->select(
                'provider',
                DB::raw('COUNT(CASE WHEN status = "cancelled" THEN 1 END) as cancelled'),
                DB::raw('COUNT(*) as total'),
                DB::raw("({$castExpression} * 100.0 / COUNT(*)) as churn_rate")
            )
            ->groupBy('provider')
            ->orderBy('churn_rate', 'desc')
            ->get()
            ->mapWithKeys(function ($item) {
                return [$item->provider => round($item->churn_rate, 2)];
            })
            ->toArray();
    }

    private function getChurnByPlan(): array
    {
        $castExpression = $this->getCastExpression();

        return Subscription::query()
            ->select(
                'plans.name as plan_name',
                DB::raw('COUNT(CASE WHEN subscriptions.status = "cancelled" THEN 1 END) as cancelled'),
                DB::raw('COUNT(*) as total'),
                DB::raw("({$castExpression} * 100.0 / COUNT(*)) as churn_rate")
            )
            ->join('plans', 'subscriptions.plan_id', '=', 'plans.id')
            ->groupBy('plans.id', 'plans.name')
            ->orderBy('churn_rate', 'desc')
            ->limit(10)
            ->get()
            ->mapWithKeys(function ($item) {
                return [$item->plan_name => round($item->churn_rate, 2)];
            })
            ->toArray();
    }

    private function getCastExpression(): string
    {
        $connection = DB::connection()->getDriverName();

        return match ($connection) {
            'sqlite' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS REAL)',
            'mysql', 'mariadb' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS DECIMAL(10,2))',
            'pgsql' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS NUMERIC)',
            'sqlsrv' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS FLOAT)',
            default => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS DECIMAL(10,2))', // fallback to MySQL format
        };
    }
}
