<?php

namespace App\Livewire\Reports;

use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Models\Payment;
use App\Domain\Shared\Traits\UsesBranchScope;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Url;
use Livewire\Component;

#[Layout('layouts.app')]
class FinancialReport extends Component
{
    use UsesBranchScope;

    #[Url]
    public string $period = 'month';

    #[Url]
    public string $dateFrom = '';

    #[Url]
    public string $dateTo = '';

    public function mount(): void
    {
        $this->authorize('reports.view');

        if (!$this->dateFrom) {
            $this->dateFrom = now()->startOfMonth()->toDateString();
        }
        if (!$this->dateTo) {
            $this->dateTo = now()->toDateString();
        }
    }

    public function updatedPeriod(): void
    {
        match ($this->period) {
            'today' => $this->dateFrom = $this->dateTo = now()->toDateString(),
            'week' => (function () {
                $this->dateFrom = now()->startOfWeek()->toDateString();
                $this->dateTo = now()->toDateString();
            })(),
            'month' => (function () {
                $this->dateFrom = now()->startOfMonth()->toDateString();
                $this->dateTo = now()->toDateString();
            })(),
            'quarter' => (function () {
                $this->dateFrom = now()->startOfQuarter()->toDateString();
                $this->dateTo = now()->toDateString();
            })(),
            'year' => (function () {
                $this->dateFrom = now()->startOfYear()->toDateString();
                $this->dateTo = now()->toDateString();
            })(),
            default => null,
        };
    }

    public function render()
    {
        $branchId = $this->getActiveBranchId();
        $payments = Payment::where('status', 'confirmed')
            ->whereBetween('created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->get();

        $totalRevenue = $payments->sum('amount');
        $paymentsByMethod = $payments->groupBy('method')
            ->map(fn ($group) => $group->sum('amount'));

        $invoices = Invoice::whereBetween('created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])
            ->when($branchId, fn ($q) => $q->whereHasMorph('billable', [\App\Domain\Participant\Models\Participant::class], fn ($pp) => $pp->where('branch_id', $branchId)))
            ->get();
        $totalInvoiced = $invoices->sum('total_amount');
        $totalOutstanding = $invoices->whereIn('status', ['sent', 'partially_paid', 'overdue'])->sum('due_amount');
        $overdueCount = $invoices->where('status', 'overdue')->count();

        $dailyRevenue = Payment::where('status', 'confirmed')
            ->whereBetween('created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->select(DB::raw('DATE(created_at) as date'), DB::raw('SUM(amount) as total'))
            ->groupBy('date')
            ->orderBy('date')
            ->pluck('total', 'date')
            ->toArray();

        $topPrograms = DB::table('invoice_items')
            ->join('invoices', 'invoices.id', '=', 'invoice_items.invoice_id')
            ->where('invoices.status', '!=', 'cancelled')
            ->whereBetween('invoices.created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])
            ->whereNotNull('invoice_items.itemable_type')
            ->when($branchId, fn ($q) => $q->whereExists(function ($s) use ($branchId) {
                $s->selectRaw('1')->from('participants')
                    ->whereColumn('participants.id', 'invoices.billable_id')
                    ->where('invoices.billable_type', \App\Domain\Participant\Models\Participant::class)
                    ->where('participants.branch_id', $branchId);
            }))
            ->select('invoice_items.description', DB::raw('SUM(invoice_items.total_amount) as revenue'), DB::raw('COUNT(*) as count'))
            ->groupBy('invoice_items.description')
            ->orderByDesc('revenue')
            ->limit(10)
            ->get();

        return view('livewire.reports.financial-report', [
            'totalRevenue' => $totalRevenue,
            'paymentsByMethod' => $paymentsByMethod,
            'totalInvoiced' => $totalInvoiced,
            'totalOutstanding' => $totalOutstanding,
            'overdueCount' => $overdueCount,
            'dailyRevenue' => $dailyRevenue,
            'topPrograms' => $topPrograms,
        ]);
    }
}
