<?php

declare(strict_types=1);

namespace App\Http\Controllers\Barangay;

use App\Enums\UserActions;
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
use App\Http\Controllers\Helpers\ResponseHelper;
use App\Models\Barangay\Blotter;
use App\Models\Barangay\BarangayBudget;
use App\Models\Barangay\BarangayProject;
use App\Models\Barangay\DocumentRequest;
use App\Models\Barangay\Household;
use App\Models\Barangay\Resident;
use Carbon\Carbon;
use Hypervel\Http\Request;
use Hypervel\Support\Facades\Auth;
use Hypervel\Support\Facades\DB;

class ReportsController
{
    public function generate(Request $request)
    {
        if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ViewGlobalReports)) {
            return ResponseHelper::returnUnauthorized();
        }

        $type = $request->input('type', 'population');
        $year = (int) $request->input('year', date('Y'));

        $data = match ($type) {
            'population'  => $this->populationReport(),
            'households'  => $this->householdsReport(),
            'documents'   => $this->documentsReport($year),
            'blotters'    => $this->blottersReport($year),
            'budget'      => $this->budgetReport($year),
            'projects'    => $this->projectsReport($year),
            default       => [],
        };

        return response()->json(['success' => true, 'data' => $data]);
    }

    private function populationReport(): array
    {
        $total = Resident::count();
        $active = Resident::where('is_active', true)->count();
        $voters = Resident::where('voter_status', true)->count();

        $genderBreakdown = Resident::select('gender', DB::raw('count(*) as count'))
            ->whereNotNull('gender')
            ->groupBy('gender')
            ->pluck('count', 'gender')
            ->toArray();

        $civilBreakdown = Resident::select('civil_status', DB::raw('count(*) as count'))
            ->whereNotNull('civil_status')
            ->groupBy('civil_status')
            ->pluck('count', 'civil_status')
            ->toArray();

        $purokBreakdown = Resident::select('purok', DB::raw('count(*) as count'))
            ->whereNotNull('purok')
            ->groupBy('purok')
            ->orderBy('purok')
            ->pluck('count', 'purok')
            ->toArray();

        // Age groups
        $now = Carbon::now();
        $ageGroups = [
            '0–12 (Children)'   => [0, 12],
            '13–17 (Youth)'     => [13, 17],
            '18–30 (Young Adult)' => [18, 30],
            '31–59 (Adult)'     => [31, 59],
            '60+ (Senior)'      => [60, 150],
        ];

        $ageBreakdown = [];
        foreach ($ageGroups as $label => [$min, $max]) {
            $from = $now->copy()->subYears($max)->format('Y-m-d');
            $to   = $now->copy()->subYears($min)->format('Y-m-d');
            $ageBreakdown[$label] = Resident::whereBetween('date_of_birth', [$from, $to])->count();
        }

        return compact('total', 'active', 'voters', 'genderBreakdown', 'civilBreakdown', 'purokBreakdown', 'ageBreakdown') + [
            'total_residents'       => $total,
            'active_residents'      => $active,
            'registered_voters'     => $voters,
            'gender_breakdown'      => $genderBreakdown,
            'civil_status_breakdown'=> $civilBreakdown,
            'purok_breakdown'       => $purokBreakdown,
            'age_breakdown'         => $ageBreakdown,
        ];
    }

    private function householdsReport(): array
    {
        $total = Household::count();
        $withElectricity = Household::where('has_electricity', true)->count();
        $withWater = Household::where('has_water', true)->count();
        $avgMembers = round(Household::withCount('chapterMembers')->avg('chapter_members_count') ?? 0, 1);

        $byOwnership = Household::select('ownership_type', DB::raw('count(*) as count'))
            ->groupBy('ownership_type')
            ->pluck('count', 'ownership_type')
            ->toArray();

        return [
            'total_households' => $total,
            'with_electricity' => $withElectricity,
            'with_water'       => $withWater,
            'avg_members'      => $avgMembers,
            'by_ownership'     => $byOwnership,
        ];
    }

    private function documentsReport(int $year): array
    {
        $base = DocumentRequest::whereYear('created_at', $year);

        $total     = (clone $base)->count();
        $claimed   = (clone $base)->where('status', 'CLAIMED')->count();
        $revenue   = (clone $base)->where('payment_status', 'PAID')->sum('base_fee');

        $byStatus = (clone $base)->select('status', DB::raw('count(*) as count'))
            ->groupBy('status')
            ->pluck('count', 'status')
            ->toArray();

        $byType = (clone $base)->select(
            'barangay_request_types.name',
            DB::raw('count(*) as count'),
            DB::raw('sum(case when barangay_document_requests.payment_status = \'PAID\' then barangay_document_requests.base_fee else 0 end) as revenue')
        )
        ->leftJoin('barangay_request_types', 'barangay_request_types.id', '=', 'barangay_document_requests.request_type_id')
        ->groupBy('barangay_request_types.name')
        ->get()
        ->toArray();

        return compact('total', 'claimed', 'revenue', 'byStatus', 'byType') + [
            'total_revenue' => $revenue,
            'by_status'     => $byStatus,
            'by_type'       => $byType,
        ];
    }

    private function blottersReport(int $year): array
    {
        $base = Blotter::whereYear('created_at', $year);

        $total    = (clone $base)->count();
        $resolved = (clone $base)->whereIn('status', ['RESOLVED', 'SETTLED'])->count();
        $pending  = (clone $base)->whereIn('status', ['FILED', 'FOR_HEARING'])->count();

        $byStatus = (clone $base)->select('status', DB::raw('count(*) as count'))
            ->groupBy('status')
            ->pluck('count', 'status')
            ->toArray();

        $byType = (clone $base)->select('incident_type', DB::raw('count(*) as count'))
            ->groupBy('incident_type')
            ->pluck('count', 'incident_type')
            ->toArray();

        return [
            'total'           => $total,
            'resolved'        => $resolved,
            'pending'         => $pending,
            'by_status'       => $byStatus,
            'by_incident_type'=> $byType,
        ];
    }

    private function budgetReport(int $year): array
    {
        $income  = BarangayBudget::income()->byYear($year)->sum('amount');
        $expense = BarangayBudget::expense()->byYear($year)->sum('amount');
        $balance = $income - $expense;

        $bySource = BarangayBudget::select('source', 'category', DB::raw('sum(amount) as amount'))
            ->byYear($year)
            ->groupBy('source', 'category')
            ->orderBy('category')
            ->get()
            ->toArray();

        return [
            'summary'   => compact('income', 'expense', 'balance') + [
                'total_income'  => $income,
                'total_expense' => $expense,
            ],
            'by_source' => $bySource,
        ];
    }

    private function projectsReport(int $year): array
    {
        $base = BarangayProject::whereYear('created_at', $year);

        $total    = (clone $base)->count();
        $ongoing  = (clone $base)->where('status', 'ONGOING')->count();
        $completed = (clone $base)->where('status', 'COMPLETED')->count();
        $budget   = (clone $base)->sum('budget');

        $byStatus = (clone $base)->select('status', DB::raw('count(*) as count'))
            ->groupBy('status')
            ->pluck('count', 'status')
            ->toArray();

        $byType = (clone $base)->select('type', DB::raw('count(*) as count'))
            ->groupBy('type')
            ->get()
            ->toArray();

        return [
            'total'        => $total,
            'ongoing'      => $ongoing,
            'completed'    => $completed,
            'total_budget' => $budget,
            'by_status'    => $byStatus,
            'by_type'      => $byType,
        ];
    }
}
