<?php

declare(strict_types=1);

namespace App\Controllers;

use DateInterval;
use DatePeriod;
use DateTime;
use Exception;

/**
 * Controller do Dashboard
 */
class DashboardController extends BaseController
{
    /**
     * Página principal do dashboard
     */
    public function index(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar se tem company_id (modo simples pode não ter)
            if (!$companyId) {
                // Buscar primeira empresa no banco
                $stmt = $this->db->prepare("SELECT id FROM companies LIMIT 1");
                $stmt->execute();
                $company = $stmt->fetch();

                if ($company) {
                    $companyId = (int) $company['id'];
                    $this->session->setCompany($companyId);
                } else {
                    // Sem empresa, exibe dashboard vazio
                    $this->view('dashboard/index', [
                        'stats' => [],
                        'vendas_status' => [],
                        'contas_receber' => [],
                        'contas_pagar' => [],
                        'top_produtos' => [],
                        'vendas_ultimos_30_dias' => [],
                        'vendas_recentes' => [],
                        'contas_vencendo' => [],
                        'finance_comparativo' => ['labels' => [], 'receber' => [], 'pagar' => []],
                        'pageTitle' => 'Dashboard'
                    ]);
                    return;
                }
            }

            // Buscar estatísticas
            $stats = $this->getStatistics($companyId);

            // Buscar dados para gráficos
            $vendasPorStatus = $this->getVendasPorStatus($companyId);
            $contasReceber = $this->getContasReceberStats($companyId);
            $contasPagar = $this->getContasPagarStats($companyId);
            $topProdutos = $this->getTopProdutos($companyId);
            $vendasUltimos30Dias = $this->getVendasUltimos30Dias($companyId);

            // Buscar listagens
            $vendasRecentes = $this->getRecentSales($companyId);
            $contasVencendo = $this->getUpcomingReceivables($companyId);
            $financeComparativo = $this->getFinanceComparisonSeries($companyId);

            $this->view('dashboard/index', [
                'stats' => $stats,
                'vendas_status' => $vendasPorStatus,
                'contas_receber' => $contasReceber,
                'contas_pagar' => $contasPagar,
                'top_produtos' => $topProdutos,
                'vendas_ultimos_30_dias' => $vendasUltimos30Dias,
                'vendas_recentes' => $vendasRecentes,
                'contas_vencendo' => $contasVencendo,
                'finance_comparativo' => $financeComparativo,
                'pageTitle' => 'Dashboard'
            ]);

        } catch (Exception $e) {
            error_log("Erro no dashboard: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());

            // Em desenvolvimento, mostra o erro
            if ($_ENV['APP_DEBUG'] ?? false) {
                die("Erro no dashboard: " . $e->getMessage() . "<br><pre>" . $e->getTraceAsString() . "</pre>");
            }

            $this->error('Erro ao carregar dashboard');
        }
    }

    /**
     * Busca estatísticas gerais
     */
    private function getStatistics(?int $companyId): array
    {
        if (!$this->db) {
            return [];
        }

        try {
            // Total de vendas no mês
            $stmt = $this->db->prepare("
                SELECT COALESCE(SUM(total), 0) as total
                FROM vendas
                WHERE company_id = :company_id
                AND MONTH(sale_date) = MONTH(CURRENT_DATE())
                AND YEAR(sale_date) = YEAR(CURRENT_DATE())
                AND status != 'cancelado'
            ");
            $stmt->execute(['company_id' => $companyId]);
            $salesTotal = $stmt->fetch()['total'] ?? 0;

            // Total de compras no mês
            $stmt = $this->db->prepare("
                SELECT COALESCE(SUM(total), 0) as total
                FROM compras
                WHERE company_id = :company_id
                AND MONTH(data_compra) = MONTH(CURRENT_DATE())
                AND YEAR(data_compra) = YEAR(CURRENT_DATE())
                AND status != 'cancelado'
            ");
            $stmt->execute(['company_id' => $companyId]);
            $purchasesTotal = $stmt->fetch()['total'] ?? 0;

            // Contas a receber em aberto
            $stmt = $this->db->prepare("
                SELECT COALESCE(SUM(amount_remaining), 0) as total
                FROM contas_receber
                WHERE company_id = :company_id
                AND status IN ('pendente', 'pago_parcial', 'vencido')
            ");
            $stmt->execute(['company_id' => $companyId]);
            $receivablesTotal = $stmt->fetch()['total'] ?? 0;

            // Contas a pagar em aberto
            $stmt = $this->db->prepare("
                SELECT COALESCE(SUM(amount_remaining), 0) as total
                FROM contas_pagar
                WHERE company_id = :company_id
                AND status IN ('pendente', 'pago_parcial', 'vencido')
            ");
            $stmt->execute(['company_id' => $companyId]);
            $payablesTotal = $stmt->fetch()['total'] ?? 0;

            // Total de produtos
            $stmt = $this->db->prepare("
                SELECT COUNT(*) as count
                FROM itens
                WHERE company_id = :company_id
                AND is_active = 1
            ");
            $stmt->execute(['company_id' => $companyId]);
            $productsCount = $stmt->fetch()['count'] ?? 0;

            // Vendas do dia
            $stmt = $this->db->prepare("
                SELECT COALESCE(SUM(total), 0) as total
                FROM vendas
                WHERE company_id = :company_id
                AND DATE(sale_date) = CURDATE()
                AND status != 'cancelada'
            ");
            $stmt->execute(['company_id' => $companyId]);
            $dailySales = $stmt->fetch()['total'] ?? 0;

            // Crescimento de vendas (comparado com mês anterior)
            $stmt = $this->db->prepare("
                SELECT COALESCE(SUM(total), 0) as total
                FROM vendas
                WHERE company_id = :company_id
                AND MONTH(sale_date) = MONTH(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH))
                AND YEAR(sale_date) = YEAR(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH))
                AND status != 'cancelada'
            ");
            $stmt->execute(['company_id' => $companyId]);
            $lastMonthSales = $stmt->fetch()['total'] ?? 0;
            $salesGrowth = $lastMonthSales > 0 ? round((($salesTotal - $lastMonthSales) / $lastMonthSales) * 100, 1) : 0;

            // Vendas do dia anterior (para comparação)
            $stmt = $this->db->prepare("
                SELECT COALESCE(SUM(total), 0) as total
                FROM vendas
                WHERE company_id = :company_id
                AND DATE(sale_date) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
                AND status != 'cancelada'
            ");
            $stmt->execute(['company_id' => $companyId]);
            $yesterdaySales = $stmt->fetch()['total'] ?? 0;
            $dailyGrowth = $yesterdaySales > 0 ? round((($dailySales - $yesterdaySales) / $yesterdaySales) * 100, 1) : 0;

            // Contagem de títulos a receber
            $stmt = $this->db->prepare("
                SELECT COUNT(*) as count
                FROM contas_receber
                WHERE company_id = :company_id
                AND status IN ('pendente', 'pago_parcial', 'vencido')
            ");
            $stmt->execute(['company_id' => $companyId]);
            $receivablesCount = $stmt->fetch()['count'] ?? 0;

            // Contagem de títulos a pagar
            $stmt = $this->db->prepare("
                SELECT COUNT(*) as count
                FROM contas_pagar
                WHERE company_id = :company_id
                AND status IN ('pendente', 'pago_parcial', 'vencido')
            ");
            $stmt->execute(['company_id' => $companyId]);
            $payablesCount = $stmt->fetch()['count'] ?? 0;

            return [
                'sales_total' => $salesTotal,
                'purchases_total' => $purchasesTotal,
                'receivables_total' => $receivablesTotal,
                'payables_total' => $payablesTotal,
                'products_count' => $productsCount,
                'daily_sales' => $dailySales,
                'sales_growth' => $salesGrowth,
                'daily_growth' => $dailyGrowth,
                'receivables_count' => $receivablesCount,
                'payables_count' => $payablesCount,
            ];

        } catch (Exception $e) {
            error_log("Erro ao buscar estatísticas: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca últimas vendas
     */
    private function getRecentSales(?int $companyId): array
    {
        if (!$this->db) {
            return [];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT v.*, p.name as cliente_name
                FROM vendas v
                LEFT JOIN pessoas p ON v.customer_id = p.id
                WHERE v.company_id = :company_id
                ORDER BY v.created_at DESC
                LIMIT 10
            ");
            $stmt->execute(['company_id' => $companyId]);

            return $stmt->fetchAll();

        } catch (Exception $e) {
            error_log("Erro ao buscar vendas: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca contas a receber vencendo
     */
    private function getUpcomingReceivables(?int $companyId): array
    {
        if (!$this->db) {
            return [];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT cr.*, p.name as pessoa_name
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                WHERE cr.company_id = :company_id
                AND cr.status IN ('pendente', 'pago_parcial', 'vencido')
                AND (
                    cr.due_date < CURRENT_DATE()
                    OR cr.due_date BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY)
                )
                ORDER BY
                    CASE WHEN cr.due_date < CURRENT_DATE() THEN 0 ELSE 1 END,
                    cr.due_date ASC
                LIMIT 10
            ");
            $stmt->execute(['company_id' => $companyId]);

            return $stmt->fetchAll();

        } catch (Exception $e) {
            error_log("Erro ao buscar recebíveis: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca contas a pagar vencendo
     */
    private function getUpcomingPayables(?int $companyId): array
    {
        if (!$this->db) {
            return [];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT cp.*, p.name as pessoa_name
                FROM contas_pagar cp
                LEFT JOIN pessoas p ON cp.pessoa_id = p.id
                WHERE cp.company_id = :company_id
                AND cp.status IN ('pendente', 'pago_parcial')
                AND cp.due_date BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY)
                ORDER BY cp.due_date ASC
                LIMIT 10
            ");
            $stmt->execute(['company_id' => $companyId]);

            return $stmt->fetchAll();

        } catch (Exception $e) {
            error_log("Erro ao buscar contas a pagar: " . $e->getMessage());
            return [];
        }
    }

    private function getFinanceComparisonSeries(?int $companyId): array
    {
        if (!$this->db) {
            return ['labels' => [], 'receber' => [], 'pagar' => []];
        }

        try {
            $base = new DateTime('first day of this month');
            $base->setTime(0, 0, 0);

            $start = clone $base;
            $end = (clone $base)->modify('+1 month');

            $period = new DatePeriod($start, new DateInterval('P1M'), $end);
            $meses = [
                '01' => 'Jan', '02' => 'Fev', '03' => 'Mar', '04' => 'Abr',
                '05' => 'Mai', '06' => 'Jun', '07' => 'Jul', '08' => 'Ago',
                '09' => 'Set', '10' => 'Out', '11' => 'Nov', '12' => 'Dez'
            ];

            $series = [];
            foreach ($period as $dataMes) {
                $key = $dataMes->format('Y-m');
                $series[$key] = [
                    'label' => ($meses[$dataMes->format('m')] ?? $dataMes->format('m')) . '/' . $dataMes->format('y'),
                    'receber' => 0.0,
                    'pagar' => 0.0
                ];
            }

            if (empty($series)) {
                return ['labels' => [], 'receber' => [], 'pagar' => []];
            }

            $stmt = $this->db->prepare("\n                SELECT DATE_FORMAT(due_date, '%Y-%m') as referencia, SUM(amount_remaining) as total\n                FROM contas_receber\n                WHERE company_id = :company_id\n                  AND due_date >= :start_date\n                  AND due_date < :end_date\n                  AND status IN ('pendente', 'pago_parcial', 'vencido')\n                GROUP BY referencia\n            ");
            $stmt->execute([
                'company_id' => $companyId,
                'start_date' => $start->format('Y-m-d'),
                'end_date' => $end->format('Y-m-d')
            ]);

            foreach ($stmt->fetchAll() as $row) {
                $ref = $row['referencia'];
                if ($ref && isset($series[$ref])) {
                    $series[$ref]['receber'] = (float) $row['total'];
                }
            }

            $stmt = $this->db->prepare("\n                SELECT DATE_FORMAT(due_date, '%Y-%m') as referencia, SUM(amount_remaining) as total\n                FROM contas_pagar\n                WHERE company_id = :company_id\n                  AND due_date >= :start_date\n                  AND due_date < :end_date\n                  AND status IN ('pendente', 'pago_parcial', 'vencido')\n                GROUP BY referencia\n            ");
            $stmt->execute([
                'company_id' => $companyId,
                'start_date' => $start->format('Y-m-d'),
                'end_date' => $end->format('Y-m-d')
            ]);

            foreach ($stmt->fetchAll() as $row) {
                $ref = $row['referencia'];
                if ($ref && isset($series[$ref])) {
                    $series[$ref]['pagar'] = (float) $row['total'];
                }
            }

            $labels = [];
            $receber = [];
            $pagar = [];

            foreach ($series as $dados) {
                $labels[] = $dados['label'];
                $receber[] = round((float) $dados['receber'], 2);
                $pagar[] = round((float) $dados['pagar'], 2);
            }

            return [
                'labels' => $labels,
                'receber' => $receber,
                'pagar' => $pagar
            ];

        } catch (Exception $e) {
            error_log('Erro ao montar série financeira: ' . $e->getMessage());
            return ['labels' => [], 'receber' => [], 'pagar' => []];
        }
    }

    /**
     * Busca vendas por status para gráfico
     */
    private function getVendasPorStatus(?int $companyId): array
    {
        if (!$this->db) {
            return ['labels' => [], 'data' => [], 'colors' => []];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT
                    status,
                    COUNT(*) as total,
                    SUM(total) as valor
                FROM vendas
                WHERE company_id = :company_id
                AND MONTH(sale_date) = MONTH(CURRENT_DATE())
                AND YEAR(sale_date) = YEAR(CURRENT_DATE())
                GROUP BY status
            ");
            $stmt->execute(['company_id' => $companyId]);
            $result = $stmt->fetchAll();

            $labels = [];
            $data = [];
            $colors = [
                'pendente' => '#ffc107',
                'concluida' => '#28a745',
                'cancelada' => '#dc3545'
            ];
            $chartColors = [];

            foreach ($result as $row) {
                $labels[] = ucfirst($row['status']);
                $data[] = (float)$row['valor'];
                $chartColors[] = $colors[$row['status']] ?? '#6c757d';
            }

            return [
                'labels' => $labels,
                'data' => $data,
                'colors' => $chartColors
            ];

        } catch (Exception $e) {
            error_log("Erro ao buscar vendas por status: " . $e->getMessage());
            return ['labels' => [], 'data' => [], 'colors' => []];
        }
    }

    /**
     * Busca estatísticas de contas a receber
     */
    private function getContasReceberStats(?int $companyId): array
    {
        if (!$this->db) {
            return ['labels' => [], 'data' => [], 'colors' => []];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT
                    CASE
                        WHEN due_date < CURRENT_DATE() THEN 'Vencidas'
                        WHEN due_date BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY) THEN 'A Vencer (7 dias)'
                        ELSE 'A Vencer'
                    END as categoria,
                    SUM(amount_remaining) as total
                FROM contas_receber
                WHERE company_id = :company_id
                AND status IN ('pendente', 'pago_parcial', 'vencido')
                GROUP BY categoria
            ");
            $stmt->execute(['company_id' => $companyId]);
            $result = $stmt->fetchAll();

            $labels = [];
            $data = [];
            $colors = [
                'Vencidas' => '#dc3545',
                'A Vencer (7 dias)' => '#ffc107',
                'A Vencer' => '#28a745'
            ];
            $chartColors = [];

            foreach ($result as $row) {
                $labels[] = $row['categoria'];
                $data[] = (float)$row['total'];
                $chartColors[] = $colors[$row['categoria']] ?? '#6c757d';
            }

            return [
                'labels' => $labels,
                'data' => $data,
                'colors' => $chartColors
            ];

        } catch (Exception $e) {
            error_log("Erro ao buscar contas a receber: " . $e->getMessage());
            return ['labels' => [], 'data' => [], 'colors' => []];
        }
    }

    /**
     * Busca estatísticas de contas a pagar
     */
    private function getContasPagarStats(?int $companyId): array
    {
        if (!$this->db) {
            return ['labels' => [], 'data' => [], 'colors' => []];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT
                    CASE
                        WHEN due_date < CURRENT_DATE() THEN 'Vencidas'
                        WHEN due_date BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY) THEN 'A Vencer (7 dias)'
                        ELSE 'A Vencer'
                    END as categoria,
                    SUM(amount_remaining) as total
                FROM contas_pagar
                WHERE company_id = :company_id
                AND status IN ('pendente', 'pago_parcial', 'vencido')
                GROUP BY categoria
            ");
            $stmt->execute(['company_id' => $companyId]);
            $result = $stmt->fetchAll();

            $labels = [];
            $data = [];
            $colors = [
                'Vencidas' => '#dc3545',
                'A Vencer (7 dias)' => '#ffc107',
                'A Vencer' => '#17a2b8'
            ];
            $chartColors = [];

            foreach ($result as $row) {
                $labels[] = $row['categoria'];
                $data[] = (float)$row['total'];
                $chartColors[] = $colors[$row['categoria']] ?? '#6c757d';
            }

            return [
                'labels' => $labels,
                'data' => $data,
                'colors' => $chartColors
            ];

        } catch (Exception $e) {
            error_log("Erro ao buscar contas a pagar: " . $e->getMessage());
            return ['labels' => [], 'data' => [], 'colors' => []];
        }
    }

    /**
     * Busca top produtos mais vendidos
     */
    private function getTopProdutos(?int $companyId): array
    {
        if (!$this->db) {
            return ['labels' => [], 'data' => [], 'colors' => []];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT
                    vi.product_name as name,
                    SUM(vi.quantity) as total_vendido
                FROM vendas_itens vi
                INNER JOIN vendas v ON vi.venda_id = v.id
                WHERE v.company_id = :company_id
                AND v.status != 'cancelado'
                AND MONTH(v.sale_date) = MONTH(CURRENT_DATE())
                AND YEAR(v.sale_date) = YEAR(CURRENT_DATE())
                GROUP BY vi.product_name
                ORDER BY total_vendido DESC
                LIMIT 5
            ");
            $stmt->execute(['company_id' => $companyId]);
            $result = $stmt->fetchAll();

            $labels = [];
            $data = [];
            $colors = ['#007bff', '#28a745', '#ffc107', '#dc3545', '#17a2b8'];

            foreach ($result as $index => $row) {
                $labels[] = $row['name'];
                $data[] = (int)$row['total_vendido'];
            }

            return [
                'labels' => $labels,
                'data' => $data,
                'colors' => array_slice($colors, 0, count($labels))
            ];

        } catch (Exception $e) {
            error_log("Erro ao buscar top produtos: " . $e->getMessage());
            return ['labels' => [], 'data' => [], 'colors' => []];
        }
    }

    /**
     * Busca vendas dos últimos 30 dias para gráfico de linha
     */
    private function getVendasUltimos30Dias(?int $companyId): array
    {
        if (!$this->db) {
            return ['labels' => [], 'data' => []];
        }

        try {
            $stmt = $this->db->prepare("
                SELECT
                    DATE(sale_date) as data,
                    COALESCE(SUM(total), 0) as total
                FROM vendas
                WHERE company_id = :company_id
                AND sale_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
                AND status != 'cancelado'
                GROUP BY DATE(sale_date)
                ORDER BY data ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $result = $stmt->fetchAll();

            $labels = [];
            $data = [];

            foreach ($result as $row) {
                $labels[] = date('d/m', strtotime($row['data']));
                $data[] = (float)$row['total'];
            }

            return [
                'labels' => $labels,
                'data' => $data
            ];

        } catch (Exception $e) {
            error_log("Erro ao buscar vendas dos últimos 30 dias: " . $e->getMessage());
            return ['labels' => [], 'data' => []];
        }
    }
}

