<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\Pwa;

use App\Enums\ExpenseCategory;
use App\Http\Controllers\Api\Pwa\Traits\RoleAwareQueries;
use App\Http\Controllers\Controller;
use App\Models\Expense;
use App\Models\Income;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class FinancialController extends Controller
{
    use RoleAwareQueries;

    /**
     * GET /api/pwa/financials
     *
     * Resumen de flujo de caja + movimientos contables del mes actual.
     * Exclusivo para el rol admin.
     */
    public function index(Request $request): JsonResponse
    {
        $role = $this->getUserPwaRole($request);
        if ($role !== 'admin') {
            return response()->json(['message' => 'No autorizado. Solo el admin puede ver la contabilidad.'], 403);
        }

        $companyId = $request->user()->company_id;
        $now = Carbon::now();
        $monthStart = $now->copy()->startOfMonth()->toDateString();
        $monthEnd = $now->copy()->endOfMonth()->toDateString();

        // ── Resumen del mes ──────────────────────────────────────────────
        $incomeTotal = (float) Income::where('company_id', $companyId)
            ->whereBetween('operation_date', [$monthStart, $monthEnd])
            ->sum('amount');

        // Solo egresos efectivos (aprobados o sin aprobación requerida): los
        // pendientes de aprobación no descuentan caja. Regla canónica scopeEffective.
        $expenseTotal = (float) Expense::where('company_id', $companyId)
            ->whereBetween('operation_date', [$monthStart, $monthEnd])
            ->effective()
            ->sum('amount');

        $netFlow = $incomeTotal - $expenseTotal;

        // Valores de las categorías de capital para incluirlas siempre en movimientos
        $capitalCategoryValues = array_map(
            fn (ExpenseCategory $c) => $c->value,
            ExpenseCategory::capitalCategories()
        );

        // ── Movimientos del mes (todos, sin limit individual) ────────────
        // Se trae todo el mes para que el merge por fecha sea correcto.
        // El límite final de 300 es más que suficiente para cualquier mes.
        $incomes = Income::where('company_id', $companyId)
            ->whereBetween('operation_date', [$monthStart, $monthEnd])
            ->with(['credit:id,client_id', 'credit.client:id,name'])
            ->orderByDesc('operation_date')
            ->orderByDesc('id')
            ->get()
            ->map(fn (Income $i) => [
                'id' => $i->id,
                'type' => 'income',
                'type_label' => 'Ingreso',
                'category' => $i->getRawOriginal('category'),
                'category_label' => $i->category?->getLabel() ?? $i->getRawOriginal('category'),
                'is_capital' => false,
                'approval_status' => 'approved',
                'amount' => (float) $i->amount,
                'date' => $i->operation_date->toDateString(),
                'notes' => $i->notes,
                'credit_id' => $i->credit_id,
                'client_name' => $i->credit?->client?->name,
            ]);

        // Gastos: aprobados/sin aprobación requerida + transacciones de capital
        // (retiros/devoluciones siempre visibles aunque estén pendientes de aprobación)
        $expenses = Expense::where('company_id', $companyId)
            ->whereBetween('operation_date', [$monthStart, $monthEnd])
            ->where(function ($q) use ($capitalCategoryValues) {
                $q->where('requires_approval', false)
                    ->orWhere('approval_status', Expense::APPROVAL_APPROVED)
                    ->orWhereIn('category', $capitalCategoryValues);
            })
            ->with(['credit:id,client_id', 'credit.client:id,name'])
            ->orderByDesc('operation_date')
            ->orderByDesc('id')
            ->get()
            ->map(fn (Expense $e) => [
                'id' => $e->id,
                'type' => 'expense',
                'type_label' => 'Gasto',
                'category' => $e->getRawOriginal('category'),
                'category_label' => $e->category?->getLabel() ?? $e->getRawOriginal('category'),
                'is_capital' => $e->getCategoryEnum()?->isCapitalTransaction() ?? false,
                'approval_status' => $e->approval_status,
                'amount' => (float) $e->amount,
                'date' => $e->operation_date->toDateString(),
                'notes' => $e->notes,
                'credit_id' => $e->credit_id,
                'client_name' => $e->credit?->client?->name,
            ]);

        // Merge ordenado por fecha DESC, desempate por id DESC, límite 300
        $movements = $incomes->concat($expenses)
            ->sortBy([['date', 'desc'], ['id', 'desc']])
            ->take(300)
            ->values();

        return response()->json([
            'summary' => [
                'month' => $now->locale('es_CO')->isoFormat('MMMM YYYY'),
                'income_total' => round($incomeTotal, 2),
                'expense_total' => round($expenseTotal, 2),
                'net_flow' => round($netFlow, 2),
                'direction' => $netFlow > 0 ? 'positive' : ($netFlow < 0 ? 'negative' : 'neutral'),
            ],
            'movements' => $movements,
            'meta' => [
                'total_incomes' => $incomes->count(),
                'total_expenses' => $expenses->count(),
                'month_start' => $monthStart,
                'month_end' => $monthEnd,
            ],
        ]);
    }
}
