<?php

namespace App\Livewire\Dashboard;

use App\Domain\Financial\Models\Payment;
use App\Domain\Training\Models\Enrollment;
use Illuminate\Support\Facades\DB;
use Livewire\Component;

class SubscriptionRevenueWidget extends Component
{
    public string $period = 'month';

    public function render()
    {
        $startDate = match ($this->period) {
            'today' => now()->startOfDay(),
            'week' => now()->startOfWeek(),
            'month' => now()->startOfMonth(),
            'year' => now()->startOfYear(),
            default => now()->startOfMonth(),
        };

        $previousStart = match ($this->period) {
            'today' => now()->subDay()->startOfDay(),
            'week' => now()->subWeek()->startOfWeek(),
            'month' => now()->subMonth()->startOfMonth(),
            'year' => now()->subYear()->startOfYear(),
            default => now()->subMonth()->startOfMonth(),
        };

        $academyId = app('current_academy')?->id;

        // Current period subscription revenue (pro-rata from invoice items)
        $totalSubscriptionRevenue = $this->getSubscriptionRevenue($startDate, null, $academyId);

        // Previous period
        $previousSubscriptionRevenue = $this->getSubscriptionRevenue($previousStart, $startDate, $academyId);

        $change = $previousSubscriptionRevenue > 0
            ? round(($totalSubscriptionRevenue - $previousSubscriptionRevenue) / $previousSubscriptionRevenue * 100, 1)
            : ($totalSubscriptionRevenue > 0 ? 100 : 0);

        // Revenue by activity
        $byActivity = collect($this->getRevenueByActivity($startDate, $academyId));

        // Top programs by subscription revenue
        $topPrograms = collect($this->getTopPrograms($startDate, $academyId));

        // Enrollment counts
        $newEnrollments = Enrollment::where('created_at', '>=', $startDate)
            ->when($academyId, fn ($q) => $q->where('academy_id', $academyId))
            ->count();

        $previousEnrollments = Enrollment::whereBetween('created_at', [$previousStart, $startDate])
            ->when($academyId, fn ($q) => $q->where('academy_id', $academyId))
            ->count();

        // Total confirmed payments this period
        $totalRevenue = Payment::where('status', 'confirmed')
            ->where('created_at', '>=', $startDate)
            ->when($academyId, fn ($q) => $q->where('academy_id', $academyId))
            ->sum('amount');

        $subscriptionPercent = $totalRevenue > 0
            ? round($totalSubscriptionRevenue / $totalRevenue * 100, 1)
            : 0;

        return view('livewire.dashboard.subscription-revenue-widget', [
            'totalSubscriptionRevenue' => $totalSubscriptionRevenue,
            'change' => $change,
            'byActivity' => $byActivity,
            'topPrograms' => $topPrograms,
            'newEnrollments' => $newEnrollments,
            'previousEnrollments' => $previousEnrollments,
            'subscriptionPercent' => $subscriptionPercent,
            'totalRevenue' => $totalRevenue,
        ]);
    }

    /**
     * Calculate subscription revenue using pro-rata allocation on bundled invoices.
     * Subscription items = invoice_items WHERE itemable_type IS NULL.
     * For each payment: payment.amount * (invoice_sub_total / invoice.total_amount)
     */
    private function getSubscriptionRevenue($from, $to, $academyId): int
    {
        $result = DB::table('payments')
            ->join('invoices', 'payments.invoice_id', '=', 'invoices.id')
            ->joinSub(
                DB::table('invoice_items')
                    ->whereNull('itemable_type')
                    ->select('invoice_id', DB::raw('SUM(total_amount) as sub_total'))
                    ->groupBy('invoice_id'),
                'sub_items',
                'sub_items.invoice_id', '=', 'invoices.id'
            )
            ->where('payments.status', 'confirmed')
            ->where('invoices.total_amount', '>', 0)
            ->where('payments.created_at', '>=', $from)
            ->when($to, fn ($q) => $q->where('payments.created_at', '<', $to))
            ->when($academyId, fn ($q) => $q->where('payments.academy_id', $academyId))
            ->select(
                DB::raw('SUM(payments.amount * sub_items.sub_total / invoices.total_amount) as subscription_revenue')
            )
            ->value('subscription_revenue');

        return (int) ($result ?? 0);
    }

    /**
     * Break down subscription revenue by activity.
     * Uses the participant's latest enrollment to determine which activity the subscription belongs to.
     * For participants with multiple activities, revenue is attributed to each proportionally.
     */
    private function getRevenueByActivity($from, $academyId)
    {
        // Get per-payment subscription amounts with participant info
        // Then group by the participant's enrolled activity
        return DB::select("
            WITH payment_sub_revenue AS (
                SELECT
                    p.id as payment_id,
                    p.amount * si.sub_total / i.total_amount as sub_revenue,
                    i.billable_id as participant_id
                FROM payments p
                JOIN invoices i ON p.invoice_id = i.id
                JOIN (
                    SELECT invoice_id, SUM(total_amount) as sub_total
                    FROM invoice_items
                    WHERE itemable_type IS NULL
                    GROUP BY invoice_id
                ) si ON si.invoice_id = i.id
                WHERE p.status = 'confirmed'
                  AND i.total_amount > 0
                  AND i.billable_type = 'App\\Domain\\Participant\\Models\\Participant'
                  AND p.created_at >= ?
                  " . ($academyId ? "AND p.academy_id = {$academyId}" : "") . "
            ),
            participant_activity AS (
                SELECT DISTINCT ON (e.participant_id)
                    e.participant_id,
                    a.id as activity_id,
                    a.name_ar as activity_name,
                    a.category
                FROM enrollments e
                JOIN training_programs tp ON e.training_program_id = tp.id
                JOIN activities a ON tp.activity_id = a.id
                WHERE e.status IN ('active', 'completed')
                ORDER BY e.participant_id, e.created_at DESC
            )
            SELECT
                pa.activity_id,
                pa.activity_name,
                pa.category,
                SUM(psr.sub_revenue) as total,
                COUNT(DISTINCT psr.participant_id) as subscriber_count
            FROM payment_sub_revenue psr
            JOIN participant_activity pa ON pa.participant_id = psr.participant_id
            GROUP BY pa.activity_id, pa.activity_name, pa.category
            ORDER BY total DESC
        ", [$from]);
    }

    /**
     * Top programs by subscription revenue collected.
     */
    private function getTopPrograms($from, $academyId)
    {
        return DB::select("
            WITH payment_sub_revenue AS (
                SELECT
                    p.id as payment_id,
                    p.amount * si.sub_total / i.total_amount as sub_revenue,
                    i.billable_id as participant_id
                FROM payments p
                JOIN invoices i ON p.invoice_id = i.id
                JOIN (
                    SELECT invoice_id, SUM(total_amount) as sub_total
                    FROM invoice_items
                    WHERE itemable_type IS NULL
                    GROUP BY invoice_id
                ) si ON si.invoice_id = i.id
                WHERE p.status = 'confirmed'
                  AND i.total_amount > 0
                  AND i.billable_type = 'App\\Domain\\Participant\\Models\\Participant'
                  AND p.created_at >= ?
                  " . ($academyId ? "AND p.academy_id = {$academyId}" : "") . "
            ),
            participant_program AS (
                SELECT DISTINCT ON (e.participant_id)
                    e.participant_id,
                    tp.id as program_id,
                    tp.name_ar as program_name,
                    a.name_ar as activity_name
                FROM enrollments e
                JOIN training_programs tp ON e.training_program_id = tp.id
                JOIN activities a ON tp.activity_id = a.id
                WHERE e.status IN ('active', 'completed')
                ORDER BY e.participant_id, e.created_at DESC
            )
            SELECT
                pp.program_id,
                pp.program_name,
                pp.activity_name,
                SUM(psr.sub_revenue) as total,
                COUNT(DISTINCT psr.participant_id) as subscriber_count
            FROM payment_sub_revenue psr
            JOIN participant_program pp ON pp.participant_id = psr.participant_id
            GROUP BY pp.program_id, pp.program_name, pp.activity_name
            ORDER BY total DESC
            LIMIT 10
        ", [$from]);
    }
}
