<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Transaction;
use App\Models\Account;
use App\Models\RecurringInstance;
use App\Models\LiabilityInstallment;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class DashboardController extends Controller
{
    /**
     * Fluxo de caixa mensal
     * Retorna receitas, despesas e saldo por mês
     * Ignora transações marcadas como transferências entre contas
     */
    public function cashflow(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        
        // Parâmetros de período (padrão: últimos 12 meses)
        $months = min((int) $request->get('months', 12), 24); // máximo 24 meses
        $endDate = Carbon::parse($request->get('end_date', now()->endOfMonth()));
        $startDate = $endDate->copy()->subMonths($months - 1)->startOfMonth();
        
        // Buscar dados mensais de transações completed (excluindo transferências)
        // Usar strftime para SQLite ou DATE_FORMAT para MySQL
        $driver = DB::connection()->getDriverName();
        $monthExpression = $driver === 'sqlite' 
            ? "strftime('%Y-%m', effective_date)" 
            : "DATE_FORMAT(effective_date, '%Y-%m')";
        
        $monthlyData = Transaction::ofUser($userId)
            ->completed()
            ->where('is_transfer', false) // Ignorar transferências entre contas
            ->whereBetween('effective_date', [$startDate, $endDate])
            ->select(
                DB::raw("$monthExpression as month"),
                DB::raw("SUM(CASE WHEN type = 'credit' THEN amount ELSE 0 END) as income"),
                DB::raw("SUM(CASE WHEN type = 'debit' THEN amount ELSE 0 END) as expense")
            )
            ->groupBy('month')
            ->orderBy('month')
            ->get()
            ->keyBy('month');
        
        // Criar array com todos os meses (mesmo sem dados)
        $result = [];
        $current = $startDate->copy();
        $cumulativeBalance = 0;
        
        // Calcular saldo inicial (antes do período) - excluindo transferências
        $initialBalance = Transaction::ofUser($userId)
            ->completed()
            ->where('is_transfer', false)
            ->where('effective_date', '<', $startDate)
            ->selectRaw("SUM(CASE WHEN type = 'credit' THEN amount ELSE -amount END) as balance")
            ->value('balance') ?? 0;
        
        $cumulativeBalance = (float) $initialBalance;
        
        while ($current <= $endDate) {
            $monthKey = $current->format('Y-m');
            $data = $monthlyData->get($monthKey);
            
            $income = (float) ($data->income ?? 0);
            $expense = (float) ($data->expense ?? 0);
            $balance = $income - $expense;
            $cumulativeBalance += $balance;
            
            $result[] = [
                'month' => $monthKey,
                'month_label' => $current->translatedFormat('M/Y'),
                'income' => $income,
                'expense' => $expense,
                'balance' => $balance,
                'cumulative_balance' => $cumulativeBalance,
            ];
            
            $current->addMonth();
        }
        
        // Totais do período
        $totals = [
            'income' => array_sum(array_column($result, 'income')),
            'expense' => array_sum(array_column($result, 'expense')),
            'balance' => array_sum(array_column($result, 'balance')),
            'average_income' => count($result) > 0 ? array_sum(array_column($result, 'income')) / count($result) : 0,
            'average_expense' => count($result) > 0 ? array_sum(array_column($result, 'expense')) / count($result) : 0,
        ];
        
        return response()->json([
            'period' => [
                'start' => $startDate->format('Y-m-d'),
                'end' => $endDate->format('Y-m-d'),
                'months' => $months,
            ],
            'data' => $result,
            'totals' => $totals,
        ]);
    }

    /**
     * Resumo geral do dashboard
     * Ignora transações marcadas como transferências entre contas
     * Agrupa valores por divisa para sistema multi-divisa
     */
    public function summary(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        
        // Saldo total das contas agrupado por divisa
        $balancesByCurrency = Account::where('user_id', $userId)
            ->where('is_active', true)
            ->where('include_in_total', true)
            ->select('currency', DB::raw('SUM(current_balance) as total'))
            ->groupBy('currency')
            ->get()
            ->mapWithKeys(function ($item) {
                return [$item->currency => (float) $item->total];
            })
            ->toArray();
        
        // Transações do mês atual agrupadas por divisa da conta (excluindo transferências)
        $currentMonth = [
            now()->startOfMonth()->format('Y-m-d'),
            now()->endOfMonth()->format('Y-m-d')
        ];
        
        $monthlyStatsByCurrency = Transaction::where('transactions.user_id', $userId)
            ->where('transactions.status', 'completed')
            ->where('transactions.is_transfer', false)
            ->whereBetween('transactions.effective_date', $currentMonth)
            ->whereNull('transactions.deleted_at')
            ->join('accounts', 'transactions.account_id', '=', 'accounts.id')
            ->select(
                'accounts.currency',
                DB::raw("SUM(CASE WHEN transactions.type = 'credit' THEN transactions.amount ELSE 0 END) as income"),
                DB::raw("SUM(CASE WHEN transactions.type = 'debit' THEN transactions.amount ELSE 0 END) as expense"),
                DB::raw("COUNT(*) as transactions_count")
            )
            ->groupBy('accounts.currency')
            ->get();
        
        $incomeByCurrency = [];
        $expenseByCurrency = [];
        $transactionsCount = 0;
        
        foreach ($monthlyStatsByCurrency as $stats) {
            $incomeByCurrency[$stats->currency] = (float) $stats->income;
            $expenseByCurrency[$stats->currency] = (float) $stats->expense;
            $transactionsCount += (int) $stats->transactions_count;
        }
        
        // Pendentes agrupadas por divisa (excluindo transferências)
        $pendingByCurrency = Transaction::where('transactions.user_id', $userId)
            ->where('transactions.status', 'pending')
            ->where('transactions.is_transfer', false)
            ->whereNull('transactions.deleted_at')
            ->join('accounts', 'transactions.account_id', '=', 'accounts.id')
            ->select(
                'accounts.currency',
                DB::raw("SUM(CASE WHEN transactions.type = 'credit' THEN transactions.planned_amount ELSE 0 END) as income"),
                DB::raw("SUM(CASE WHEN transactions.type = 'debit' THEN transactions.planned_amount ELSE 0 END) as expense"),
                DB::raw("COUNT(*) as count")
            )
            ->groupBy('accounts.currency')
            ->get();
        
        $pendingIncomeByCurrency = [];
        $pendingExpenseByCurrency = [];
        $pendingCount = 0;
        
        foreach ($pendingByCurrency as $pending) {
            $pendingIncomeByCurrency[$pending->currency] = (float) $pending->income;
            $pendingExpenseByCurrency[$pending->currency] = (float) $pending->expense;
            $pendingCount += (int) $pending->count;
        }
        
        // Atrasadas (vencidas) agrupadas por divisa - excluindo transferências
        $overdueByCurrency = Transaction::where('transactions.user_id', $userId)
            ->where('transactions.status', 'pending')
            ->where('transactions.is_transfer', false)
            ->where('transactions.planned_date', '<', now()->startOfDay())
            ->whereNull('transactions.deleted_at')
            ->join('accounts', 'transactions.account_id', '=', 'accounts.id')
            ->select(
                'accounts.currency',
                DB::raw("SUM(transactions.planned_amount) as total"),
                DB::raw("COUNT(*) as count")
            )
            ->groupBy('accounts.currency')
            ->get();
        
        $overdueTotalByCurrency = [];
        $overdueCount = 0;
        
        foreach ($overdueByCurrency as $overdue) {
            $overdueTotalByCurrency[$overdue->currency] = (float) $overdue->total;
            $overdueCount += (int) $overdue->count;
        }
        
        // Determinar divisa principal (a com maior saldo ou primeira encontrada)
        $primaryCurrency = !empty($balancesByCurrency) ? array_key_first($balancesByCurrency) : 'BRL';
        
        return response()->json([
            // Compatibilidade com versão anterior (usando primeira divisa)
            'total_balance' => (float) ($balancesByCurrency[$primaryCurrency] ?? 0),
            'current_month' => [
                'income' => (float) ($incomeByCurrency[$primaryCurrency] ?? 0),
                'expense' => (float) ($expenseByCurrency[$primaryCurrency] ?? 0),
                'balance' => (float) (($incomeByCurrency[$primaryCurrency] ?? 0) - ($expenseByCurrency[$primaryCurrency] ?? 0)),
                'transactions_count' => $transactionsCount,
            ],
            'pending' => [
                'income' => (float) ($pendingIncomeByCurrency[$primaryCurrency] ?? 0),
                'expense' => (float) ($pendingExpenseByCurrency[$primaryCurrency] ?? 0),
                'count' => $pendingCount,
            ],
            'overdue' => [
                'total' => (float) ($overdueTotalByCurrency[$primaryCurrency] ?? 0),
                'count' => $overdueCount,
            ],
            // Novos campos multi-divisa
            'primary_currency' => $primaryCurrency,
            'balances_by_currency' => $balancesByCurrency,
            'current_month_by_currency' => [
                'income' => $incomeByCurrency,
                'expense' => $expenseByCurrency,
            ],
            'pending_by_currency' => [
                'income' => $pendingIncomeByCurrency,
                'expense' => $pendingExpenseByCurrency,
            ],
            'overdue_by_currency' => $overdueTotalByCurrency,
        ]);
    }

    /**
     * Despesas por categoria (últimos N meses)
     * Ignora transações marcadas como transferências entre contas
     */
    public function expensesByCategory(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        $months = min((int) $request->get('months', 3), 12);
        
        $startDate = now()->subMonths($months - 1)->startOfMonth();
        $endDate = now()->endOfMonth();
        
        $data = Transaction::ofUser($userId)
            ->completed()
            ->where('is_transfer', false) // Ignorar transferências entre contas
            ->where('type', 'debit')
            ->whereBetween('effective_date', [$startDate, $endDate])
            ->whereNotNull('category_id')
            ->select(
                'category_id',
                DB::raw('SUM(amount) as total'),
                DB::raw('COUNT(*) as count')
            )
            ->groupBy('category_id')
            ->with('category:id,name,color,icon')
            ->orderByDesc('total')
            ->limit(10)
            ->get();
        
        $total = $data->sum('total');
        
        $result = $data->map(function ($item) use ($total) {
            return [
                'category_id' => $item->category_id,
                'category_name' => $item->category->name ?? 'Sem categoria',
                'category_color' => $item->category->color ?? '#6b7280',
                'category_icon' => $item->category->icon ?? 'bi-tag',
                'total' => (float) $item->total,
                'count' => (int) $item->count,
                'percentage' => $total > 0 ? round(($item->total / $total) * 100, 1) : 0,
            ];
        });
        
        return response()->json([
            'period' => [
                'start' => $startDate->format('Y-m-d'),
                'end' => $endDate->format('Y-m-d'),
                'months' => $months,
            ],
            'data' => $result,
            'total' => (float) $total,
        ]);
    }

    /**
     * Receitas por categoria (últimos N meses)
     * Ignora transações marcadas como transferências entre contas
     */
    public function incomeByCategory(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        $months = min((int) $request->get('months', 3), 12);
        
        $startDate = now()->subMonths($months - 1)->startOfMonth();
        $endDate = now()->endOfMonth();
        
        $data = Transaction::ofUser($userId)
            ->completed()
            ->where('is_transfer', false) // Ignorar transferências entre contas
            ->where('type', 'credit')
            ->whereBetween('effective_date', [$startDate, $endDate])
            ->whereNotNull('category_id')
            ->select(
                'category_id',
                DB::raw('SUM(amount) as total'),
                DB::raw('COUNT(*) as count')
            )
            ->groupBy('category_id')
            ->with('category:id,name,color,icon')
            ->orderByDesc('total')
            ->limit(10)
            ->get();
        
        $total = $data->sum('total');
        
        $result = $data->map(function ($item) use ($total) {
            return [
                'category_id' => $item->category_id,
                'category_name' => $item->category->name ?? 'Sem categoria',
                'category_color' => $item->category->color ?? '#6b7280',
                'category_icon' => $item->category->icon ?? 'bi-tag',
                'total' => (float) $item->total,
                'count' => (int) $item->count,
                'percentage' => $total > 0 ? round(($item->total / $total) * 100, 1) : 0,
            ];
        });
        
        return response()->json([
            'period' => [
                'start' => $startDate->format('Y-m-d'),
                'end' => $endDate->format('Y-m-d'),
                'months' => $months,
            ],
            'data' => $result,
            'total' => (float) $total,
        ]);
    }

    /**
     * Análise de diferenças entre valores planejados e efetivos
     * Mostra sobrepagamentos e subpagamentos
     */
    public function paymentVariances(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        $months = min((int) $request->get('months', 3), 12);
        
        $startDate = now()->subMonths($months - 1)->startOfMonth();
        $endDate = now()->endOfMonth();
        
        // Buscar transações completed com diferença entre planned_amount e amount
        $transactions = Transaction::ofUser($userId)
            ->completed()
            ->where('is_transfer', false)
            ->whereBetween('effective_date', [$startDate, $endDate])
            ->whereRaw('ABS(amount - planned_amount) > 0.01') // Diferença maior que 1 centavo
            ->with(['category:id,name,color,icon', 'account:id,name'])
            ->orderByRaw('ABS(amount - planned_amount) DESC')
            ->limit(50)
            ->get();
        
        $result = $transactions->map(function ($t) {
            $variance = $t->amount - $t->planned_amount;
            $variancePercent = $t->planned_amount > 0 
                ? round(($variance / $t->planned_amount) * 100, 2) 
                : 0;
            
            // Calcular dias de atraso (diferença entre effective_date e planned_date)
            $delayDays = null;
            if ($t->planned_date && $t->effective_date) {
                $delayDays = $t->planned_date->diffInDays($t->effective_date, false);
                // Positivo = pago depois do planejado (atrasado)
                // Negativo = pago antes do planejado (adiantado)
            }
            
            return [
                'id' => $t->id,
                'description' => $t->description,
                'type' => $t->type,
                'planned_amount' => (float) $t->planned_amount,
                'actual_amount' => (float) $t->amount,
                'variance' => (float) $variance,
                'variance_percent' => $variancePercent,
                'effective_date' => $t->effective_date->format('Y-m-d'),
                'planned_date' => $t->planned_date ? $t->planned_date->format('Y-m-d') : null,
                'delay_days' => $delayDays,
                'category' => $t->category ? [
                    'id' => $t->category->id,
                    'name' => $t->category->name,
                    'color' => $t->category->color,
                ] : null,
                'account' => $t->account ? [
                    'id' => $t->account->id,
                    'name' => $t->account->name,
                ] : null,
            ];
        });
        
        // Calcular totais
        $overpayments = $result->filter(fn($t) => $t['variance'] > 0);
        $underpayments = $result->filter(fn($t) => $t['variance'] < 0);
        
        // Agrupar por mês para o gráfico
        $byMonth = $transactions->groupBy(function ($t) {
            return $t->effective_date->format('Y-m');
        })->map(function ($items, $month) {
            $over = $items->filter(fn($t) => $t->amount > $t->planned_amount)
                ->sum(fn($t) => $t->amount - $t->planned_amount);
            $under = $items->filter(fn($t) => $t->amount < $t->planned_amount)
                ->sum(fn($t) => $t->planned_amount - $t->amount);
            
            return [
                'month' => $month,
                'overpayment' => round($over, 2),
                'underpayment' => round($under, 2),
                'net' => round($over - $under, 2),
                'count' => $items->count(),
            ];
        })->sortKeys()->values();
        
        return response()->json([
            'period' => [
                'start' => $startDate->format('Y-m-d'),
                'end' => $endDate->format('Y-m-d'),
                'months' => $months,
            ],
            'summary' => [
                'total_overpayment' => round($overpayments->sum('variance'), 2),
                'total_underpayment' => round(abs($underpayments->sum('variance')), 2),
                'net_variance' => round($result->sum('variance'), 2),
                'overpayment_count' => $overpayments->count(),
                'underpayment_count' => $underpayments->count(),
            ],
            'by_month' => $byMonth,
            'transactions' => $result,
        ]);
    }

    /**
     * Dados do calendário para o dashboard
     * Retorna transações e instâncias recorrentes pendentes por data
     */
    public function calendar(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        
        // Período: mês atual por padrão, ou o mês especificado
        $year = (int) $request->get('year', now()->year);
        $month = (int) $request->get('month', now()->month);
        
        $startDate = Carbon::create($year, $month, 1)->startOfMonth();
        $endDate = $startDate->copy()->endOfMonth();
        
        // Buscar transações do período
        $transactions = Transaction::ofUser($userId)
            ->whereBetween('effective_date', [$startDate, $endDate])
            ->with(['account:id,name,currency', 'category:id,name,color,icon'])
            ->orderBy('effective_date')
            ->get()
            ->map(function ($t) {
                return [
                    'id' => $t->id,
                    'type' => 'transaction',
                    'date' => $t->effective_date->format('Y-m-d'),
                    'description' => $t->description,
                    'amount' => (float) $t->amount,
                    'transaction_type' => $t->type,
                    'status' => $t->status,
                    'is_transfer' => $t->is_transfer,
                    'account' => $t->account ? [
                        'id' => $t->account->id,
                        'name' => $t->account->name,
                        'currency' => $t->account->currency,
                    ] : null,
                    'category' => $t->category ? [
                        'id' => $t->category->id,
                        'name' => $t->category->name,
                        'color' => $t->category->color,
                        'icon' => $t->category->icon,
                    ] : null,
                ];
            });
        
        // Buscar instâncias recorrentes pendentes do período
        $recurringInstances = RecurringInstance::where('user_id', $userId)
            ->whereBetween('due_date', [$startDate, $endDate])
            ->where('status', 'pending')
            ->whereNull('transaction_id') // Não reconciliadas
            ->with(['template:id,name,type,planned_amount,account_id,category_id', 'template.account:id,name,currency', 'template.category:id,name,color,icon'])
            ->orderBy('due_date')
            ->get()
            ->map(function ($ri) {
                return [
                    'id' => $ri->id,
                    'type' => 'recurring',
                    'date' => $ri->due_date->format('Y-m-d'),
                    'description' => $ri->template->name ?? 'Recorrência',
                    'amount' => (float) $ri->planned_amount,
                    'transaction_type' => $ri->template->type ?? 'debit',
                    'status' => $ri->status,
                    'occurrence_number' => $ri->occurrence_number,
                    'template_id' => $ri->recurring_template_id,
                    'account' => $ri->template && $ri->template->account ? [
                        'id' => $ri->template->account->id,
                        'name' => $ri->template->account->name,
                        'currency' => $ri->template->account->currency,
                    ] : null,
                    'category' => $ri->template && $ri->template->category ? [
                        'id' => $ri->template->category->id,
                        'name' => $ri->template->category->name,
                        'color' => $ri->template->category->color,
                        'icon' => $ri->template->category->icon,
                    ] : null,
                ];
            });
        
        // Combinar e agrupar por data
        $allItems = $transactions->concat($recurringInstances);
        
        $byDate = $allItems->groupBy('date')->map(function ($items, $date) {
            return [
                'date' => $date,
                'items' => $items->values(),
                'total_credit' => $items->where('transaction_type', 'credit')->sum('amount'),
                'total_debit' => $items->where('transaction_type', 'debit')->sum('amount'),
                'has_transactions' => $items->where('type', 'transaction')->count() > 0,
                'has_recurring' => $items->where('type', 'recurring')->count() > 0,
                'pending_count' => $items->whereIn('status', ['pending', 'scheduled'])->count(),
            ];
        })->values();
        
        // Resumo do mês (excluindo transferências entre contas)
        $nonTransferTransactions = $transactions->where('is_transfer', false);
        $summary = [
            'transactions_count' => $nonTransferTransactions->count(),
            'recurring_count' => $recurringInstances->count(),
            'total_income' => $nonTransferTransactions->where('transaction_type', 'credit')->sum('amount'),
            'total_expense' => $nonTransferTransactions->where('transaction_type', 'debit')->sum('amount'),
            'pending_recurring' => $recurringInstances->count(),
            'pending_recurring_amount' => $recurringInstances->sum('amount'),
        ];
        
        return response()->json([
            'period' => [
                'year' => $year,
                'month' => $month,
                'start' => $startDate->format('Y-m-d'),
                'end' => $endDate->format('Y-m-d'),
            ],
            'by_date' => $byDate,
            'summary' => $summary,
        ]);
    }

    /**
     * Transações e recorrências de um dia específico
     */
    public function calendarDay(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        $date = Carbon::parse($request->get('date', now()->format('Y-m-d')));
        
        // Buscar transações do dia
        $transactions = Transaction::ofUser($userId)
            ->whereDate('effective_date', $date)
            ->with(['account:id,name,currency', 'category:id,name,color,icon'])
            ->orderBy('effective_date')
            ->orderBy('created_at')
            ->get()
            ->map(function ($t) {
                return [
                    'id' => $t->id,
                    'type' => 'transaction',
                    'date' => $t->effective_date->format('Y-m-d'),
                    'description' => $t->description,
                    'amount' => (float) $t->amount,
                    'transaction_type' => $t->type,
                    'status' => $t->status,
                    'is_transfer' => $t->is_transfer,
                    'notes' => $t->notes,
                    'account' => $t->account ? [
                        'id' => $t->account->id,
                        'name' => $t->account->name,
                        'currency' => $t->account->currency,
                    ] : null,
                    'category' => $t->category ? [
                        'id' => $t->category->id,
                        'name' => $t->category->name,
                        'color' => $t->category->color,
                        'icon' => $t->category->icon,
                    ] : null,
                ];
            });
        
        // Buscar instâncias recorrentes pendentes do dia
        $recurringInstances = RecurringInstance::where('user_id', $userId)
            ->whereDate('due_date', $date)
            ->where('status', 'pending')
            ->whereNull('transaction_id')
            ->with(['template:id,name,type,planned_amount,account_id,category_id,description,transaction_description', 'template.account:id,name,currency', 'template.category:id,name,color,icon'])
            ->orderBy('due_date')
            ->get()
            ->map(function ($ri) {
                return [
                    'id' => $ri->id,
                    'type' => 'recurring',
                    'date' => $ri->due_date->format('Y-m-d'),
                    'description' => $ri->template->name ?? 'Recorrência',
                    'amount' => (float) $ri->planned_amount,
                    'transaction_type' => $ri->template->type ?? 'debit',
                    'status' => $ri->status,
                    'occurrence_number' => $ri->occurrence_number,
                    'template_id' => $ri->recurring_template_id,
                    'notes' => $ri->template->description ?? null,
                    'account' => $ri->template && $ri->template->account ? [
                        'id' => $ri->template->account->id,
                        'name' => $ri->template->account->name,
                        'currency' => $ri->template->account->currency,
                    ] : null,
                    'category' => $ri->template && $ri->template->category ? [
                        'id' => $ri->template->category->id,
                        'name' => $ri->template->category->name,
                        'color' => $ri->template->category->color,
                        'icon' => $ri->template->category->icon,
                    ] : null,
                ];
            });
        
        // Combinar
        $allItems = $transactions->concat($recurringInstances);
        
        // Para o resumo, excluir transferências entre contas
        $nonTransferItems = $allItems->filter(fn($item) => !($item['is_transfer'] ?? false));
        
        return response()->json([
            'date' => $date->format('Y-m-d'),
            'date_formatted' => $date->translatedFormat('l, d F Y'),
            'items' => $allItems->values(),
            'summary' => [
                'transactions_count' => $transactions->count(),
                'recurring_count' => $recurringInstances->count(),
                'total_credit' => $nonTransferItems->where('transaction_type', 'credit')->sum('amount'),
                'total_debit' => $nonTransferItems->where('transaction_type', 'debit')->sum('amount'),
            ],
        ]);
    }

    /**
     * Transações pendentes dos próximos dias (incluindo hoje)
     */
    public function upcomingTransactions(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        $days = min((int) $request->get('days', 7), 30); // máximo 30 dias
        
        $startDate = now()->startOfDay();
        $endDate = now()->addDays($days - 1)->endOfDay();
        
        // Buscar transações pendentes do período
        $transactions = Transaction::ofUser($userId)
            ->whereIn('status', ['pending', 'scheduled'])
            ->whereBetween('effective_date', [$startDate, $endDate])
            ->with(['account:id,name,currency', 'category:id,name,color,icon'])
            ->orderBy('effective_date')
            ->orderBy('created_at')
            ->get()
            ->map(function ($t) {
                return [
                    'id' => $t->id,
                    'type' => 'transaction',
                    'date' => $t->effective_date->format('Y-m-d'),
                    'date_formatted' => $t->effective_date->translatedFormat('D, d M'),
                    'description' => $t->description,
                    'amount' => (float) $t->amount,
                    'currency' => $t->account->currency ?? 'EUR',
                    'transaction_type' => $t->type,
                    'status' => $t->status,
                    'is_transfer' => $t->is_transfer,
                    'days_until' => (int) now()->startOfDay()->diffInDays($t->effective_date, false),
                    'account' => $t->account ? [
                        'id' => $t->account->id,
                        'name' => $t->account->name,
                        'currency' => $t->account->currency,
                    ] : null,
                    'category' => $t->category ? [
                        'id' => $t->category->id,
                        'name' => $t->category->name,
                        'color' => $t->category->color,
                        'icon' => $t->category->icon,
                    ] : null,
                ];
            });
        
        // Buscar instâncias recorrentes pendentes do período
        $recurringInstances = RecurringInstance::where('user_id', $userId)
            ->where('status', 'pending')
            ->whereNull('transaction_id')
            ->whereBetween('due_date', [$startDate, $endDate])
            ->with(['template:id,name,type,planned_amount,account_id,category_id', 'template.account:id,name,currency', 'template.category:id,name,color,icon'])
            ->orderBy('due_date')
            ->get()
            ->map(function ($ri) {
                return [
                    'id' => $ri->id,
                    'type' => 'recurring',
                    'date' => $ri->due_date->format('Y-m-d'),
                    'date_formatted' => $ri->due_date->translatedFormat('D, d M'),
                    'description' => $ri->template->name ?? 'Recorrência',
                    'amount' => (float) $ri->planned_amount,
                    'currency' => $ri->template->account->currency ?? 'EUR',
                    'transaction_type' => $ri->template->type ?? 'debit',
                    'status' => $ri->status,
                    'occurrence_number' => $ri->occurrence_number,
                    'template_id' => $ri->recurring_template_id,
                    'days_until' => (int) now()->startOfDay()->diffInDays($ri->due_date, false),
                    'account' => $ri->template && $ri->template->account ? [
                        'id' => $ri->template->account->id,
                        'name' => $ri->template->account->name,
                        'currency' => $ri->template->account->currency,
                    ] : null,
                    'category' => $ri->template && $ri->template->category ? [
                        'id' => $ri->template->category->id,
                        'name' => $ri->template->category->name,
                        'color' => $ri->template->category->color,
                        'icon' => $ri->template->category->icon,
                    ] : null,
                ];
            });
        
        // Combinar e ordenar por data
        $allItems = $transactions->concat($recurringInstances)
            ->sortBy('date')
            ->values();
        
        // Agrupar por data
        $byDate = $allItems->groupBy('date')->map(function ($items, $date) {
            $carbonDate = Carbon::parse($date);
            $daysUntil = (int) now()->startOfDay()->diffInDays($carbonDate, false);
            
            return [
                'date' => $date,
                'date_formatted' => $carbonDate->translatedFormat('l, d M'),
                'days_until' => $daysUntil,
                'is_today' => $daysUntil === 0,
                'items' => $items->values(),
                'total_credit' => $items->where('transaction_type', 'credit')->where('is_transfer', '!==', true)->sum('amount'),
                'total_debit' => $items->where('transaction_type', 'debit')->where('is_transfer', '!==', true)->sum('amount'),
            ];
        })->values();
        
        // Totais gerais (excluindo transferências)
        $nonTransferItems = $allItems->filter(fn($item) => !($item['is_transfer'] ?? false));
        $summary = [
            'total_items' => $allItems->count(),
            'transactions_count' => $transactions->count(),
            'recurring_count' => $recurringInstances->count(),
            'total_credit' => $nonTransferItems->where('transaction_type', 'credit')->sum('amount'),
            'total_debit' => $nonTransferItems->where('transaction_type', 'debit')->sum('amount'),
        ];
        
        return response()->json([
            'period' => [
                'start' => $startDate->format('Y-m-d'),
                'end' => $endDate->format('Y-m-d'),
                'days' => $days,
            ],
            'by_date' => $byDate,
            'items' => $allItems,
            'summary' => $summary,
        ]);
    }

    /**
     * Transações em atraso (vencidas e não pagas)
     */
    public function overdueTransactions(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        $limit = min((int) $request->get('limit', 50), 100); // máximo 100
        
        $today = now()->startOfDay();
        
        // Buscar transações pendentes com data planejada no passado
        $transactions = Transaction::ofUser($userId)
            ->whereIn('status', ['pending', 'scheduled'])
            ->where('is_transfer', false)
            ->where('planned_date', '<', $today)
            ->with(['account:id,name,currency', 'category:id,name,color,icon'])
            ->orderBy('planned_date')
            ->limit($limit)
            ->get()
            ->map(function ($t) use ($today) {
                $plannedDate = Carbon::parse($t->planned_date);
                $daysOverdue = (int) $plannedDate->diffInDays($today);
                
                return [
                    'id' => $t->id,
                    'type' => 'transaction',
                    'planned_date' => $t->planned_date->format('Y-m-d'),
                    'planned_date_formatted' => $t->planned_date->translatedFormat('D, d M Y'),
                    'description' => $t->description,
                    'amount' => (float) ($t->planned_amount ?? $t->amount),
                    'currency' => $t->account->currency ?? 'EUR',
                    'transaction_type' => $t->type,
                    'status' => $t->status,
                    'days_overdue' => $daysOverdue,
                    'account' => $t->account ? [
                        'id' => $t->account->id,
                        'name' => $t->account->name,
                        'currency' => $t->account->currency,
                    ] : null,
                    'category' => $t->category ? [
                        'id' => $t->category->id,
                        'name' => $t->category->name,
                        'color' => $t->category->color,
                        'icon' => $t->category->icon,
                    ] : null,
                ];
            });
        
        // Buscar instâncias recorrentes em atraso
        $recurringInstances = RecurringInstance::where('user_id', $userId)
            ->where('status', 'pending')
            ->whereNull('transaction_id')
            ->where('due_date', '<', $today)
            ->with(['template:id,name,type,planned_amount,account_id,category_id', 'template.account:id,name,currency', 'template.category:id,name,color,icon'])
            ->orderBy('due_date')
            ->limit($limit)
            ->get()
            ->map(function ($ri) use ($today) {
                $dueDate = Carbon::parse($ri->due_date);
                $daysOverdue = (int) $dueDate->diffInDays($today);
                
                return [
                    'id' => $ri->id,
                    'type' => 'recurring',
                    'planned_date' => $ri->due_date->format('Y-m-d'),
                    'planned_date_formatted' => $ri->due_date->translatedFormat('D, d M Y'),
                    'description' => $ri->template->name ?? 'Recorrência',
                    'amount' => (float) $ri->planned_amount,
                    'currency' => $ri->template->account->currency ?? 'EUR',
                    'transaction_type' => $ri->template->type ?? 'debit',
                    'status' => $ri->status,
                    'occurrence_number' => $ri->occurrence_number,
                    'template_id' => $ri->recurring_template_id,
                    'days_overdue' => $daysOverdue,
                    'account' => $ri->template && $ri->template->account ? [
                        'id' => $ri->template->account->id,
                        'name' => $ri->template->account->name,
                        'currency' => $ri->template->account->currency,
                    ] : null,
                    'category' => $ri->template && $ri->template->category ? [
                        'id' => $ri->template->category->id,
                        'name' => $ri->template->category->name,
                        'color' => $ri->template->category->color,
                        'icon' => $ri->template->category->icon,
                    ] : null,
                ];
            });
        
        // Buscar parcelas de passivo em atraso
        $liabilityInstallments = LiabilityInstallment::whereHas('liabilityAccount', function ($query) use ($userId) {
                $query->where('user_id', $userId);
            })
            ->where('status', 'pending')
            ->where('due_date', '<', $today)
            ->with(['liabilityAccount:id,name,creditor,currency'])
            ->orderBy('due_date')
            ->limit($limit)
            ->get()
            ->map(function ($li) use ($today) {
                $dueDate = Carbon::parse($li->due_date);
                $daysOverdue = (int) $dueDate->diffInDays($today);
                
                return [
                    'id' => $li->id,
                    'type' => 'liability',
                    'planned_date' => $li->due_date->format('Y-m-d'),
                    'planned_date_formatted' => $li->due_date->translatedFormat('D, d M Y'),
                    'description' => $li->liabilityAccount->name . ' - Parcela ' . $li->installment_number,
                    'amount' => (float) $li->amount,
                    'currency' => $li->liabilityAccount->currency ?? 'EUR',
                    'transaction_type' => 'debit',
                    'status' => $li->status,
                    'installment_number' => $li->installment_number,
                    'liability_account_id' => $li->liability_account_id,
                    'creditor' => $li->liabilityAccount->creditor,
                    'days_overdue' => $daysOverdue,
                    'account' => null,
                    'category' => null,
                ];
            });
        
        // Combinar e ordenar por dias em atraso (mais antigo primeiro)
        $allItems = $transactions->concat($recurringInstances)->concat($liabilityInstallments)
            ->sortByDesc('days_overdue')
            ->values();
        
        // Agrupar por faixa de atraso
        $byRange = collect([
            ['key' => 'critical', 'min' => 30, 'max' => PHP_INT_MAX, 'label' => '> 30 dias'],
            ['key' => 'high', 'min' => 15, 'max' => 29, 'label' => '15-30 dias'],
            ['key' => 'medium', 'min' => 7, 'max' => 14, 'label' => '7-14 dias'],
            ['key' => 'low', 'min' => 1, 'max' => 6, 'label' => '1-6 dias'],
        ])->map(function ($range) use ($allItems) {
            $items = $allItems->filter(function ($item) use ($range) {
                return $item['days_overdue'] >= $range['min'] && $item['days_overdue'] <= $range['max'];
            })->values();
            
            return [
                'key' => $range['key'],
                'label' => $range['label'],
                'min_days' => $range['min'],
                'max_days' => $range['max'] === PHP_INT_MAX ? null : $range['max'],
                'items' => $items,
                'count' => $items->count(),
                'total' => $items->sum('amount'),
            ];
        })->filter(fn($range) => $range['count'] > 0)->values();
        
        // Totais gerais
        $summary = [
            'total_items' => $allItems->count(),
            'transactions_count' => $transactions->count(),
            'recurring_count' => $recurringInstances->count(),
            'liability_count' => $liabilityInstallments->count(),
            'total_amount' => $allItems->sum('amount'),
            'total_credit' => $allItems->where('transaction_type', 'credit')->sum('amount'),
            'total_debit' => $allItems->where('transaction_type', 'debit')->sum('amount'),
            'oldest_date' => $allItems->isNotEmpty() ? $allItems->first()['planned_date'] : null,
            'max_days_overdue' => $allItems->isNotEmpty() ? $allItems->first()['days_overdue'] : 0,
        ];
        
        return response()->json([
            'by_range' => $byRange,
            'items' => $allItems->take($limit),
            'summary' => $summary,
        ]);
    }
}
