<?php

declare(strict_types=1);

namespace App\Controllers;

use Exception;

class ExpedicaoController extends BaseController
{
    /**
     * Status das vendas considerados no fluxo de expedição
     */
    private array $allowedStatuses = ['pendente', 'realizado', 'faturamento', 'expedicao', 'finalizado'];

    public function index(): void
    {
        // Verificar permissão de visualização
        if (!$this->canView('expedicao')) {
            $this->response->forbidden('Você não tem permissão para visualizar expedição.');
            return;
        }

        try {
            $companyId = $this->getCompanyId();
            $statusFiltro = $this->request->get('status', '');
            $clienteIdFiltro = $this->request->get('cliente_id', '');
            $dataInicio = $this->request->get('data_inicio', '');
            $dataFim = $this->request->get('data_fim', '');

            $statusDisponiveis = $this->carregarStatusExpedicao($companyId);
            $statusCodigos = array_column($statusDisponiveis, 'codigo');

            if (empty($statusCodigos)) {
                $statusCodigos = $this->allowedStatuses;
            }

            $params = ['company_id' => $companyId];
            $statusPlaceholders = [];
            foreach ($statusCodigos as $idx => $codigo) {
                $key = ':status_' . $idx;
                $statusPlaceholders[] = $key;
                $params[$key] = $codigo;
            }

            $query = "
                SELECT
                    v.id,
                    v.sale_number,
                    v.sale_date,
                    v.status,
                    v.total,
                    v.chave_nfe,
                    v.numero_nfe,
                    v.conferido,
                    v.conferido_em,
                    v.dispatch_transportadora,
                    v.dispatch_rastreio,
                    v.dispatch_volumes,
                    v.dispatch_responsavel,
                    v.dispatch_data,
                    p.id AS customer_id,
                    p.name AS customer_name,
                    u.name AS vendor_name
                FROM vendas v
                LEFT JOIN pessoas p ON v.customer_id = p.id
                LEFT JOIN users u ON v.vendor_id = u.id
                WHERE v.company_id = :company_id
                  AND v.modulo_origem = 'venda'
                  AND v.status IN (" . implode(',', $statusPlaceholders) . ")
            ";

            if (!empty($statusFiltro)) {
                $query .= " AND v.status = :status_filtro";
                $params['status_filtro'] = $statusFiltro;
            }

            if (!empty($clienteIdFiltro)) {
                $query .= " AND v.customer_id = :cliente_id";
                $params['cliente_id'] = $clienteIdFiltro;
            }

            if (!empty($dataInicio)) {
                $query .= " AND v.sale_date >= :data_inicio";
                $params['data_inicio'] = $dataInicio;
            }

            if (!empty($dataFim)) {
                $query .= " AND v.sale_date <= :data_fim";
                $params['data_fim'] = $dataFim;
            }

            $query .= " ORDER BY v.sale_date DESC, v.id DESC";

            $stmt = $this->db->prepare($query);
            $stmt->execute($params);
            $vendas = $stmt->fetchAll();

            // Lista de clientes para o filtro
            $clientes = $this->carregarClientes($companyId);

            $this->view('expedicao/index', [
                'pageTitle' => 'Expedição',
                'activeMenu' => 'expedicao',
                'vendas' => $vendas ?: [],
                'statusDisponiveis' => $statusDisponiveis,
                'filtroStatus' => $statusFiltro,
                'clientes' => $clientes,
                'filtroClienteId' => $clienteIdFiltro,
                'dataInicio' => $dataInicio,
                'dataFim' => $dataFim
            ]);
        } catch (Exception $e) {
            error_log("Erro ao carregar expedição: " . $e->getMessage());
            $this->error('Erro ao carregar expedição');
        }
    }

    public function show(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $saleNumber = trim((string) $this->request->get('sale_number', ''));

            if (!$id && $saleNumber === '') {
                $this->error('Informe o ID ou o número da venda (DAV)');
                return;
            }

            if ($saleNumber !== '') {
                $venda = $this->buscarVendaPorNumero($saleNumber);
            } else {
                $venda = $this->buscarVenda($id);
            }
            if (!$venda) {
                $this->error('Venda não encontrada');
                return;
            }

            $this->success('Dados carregados', ['venda' => $venda]);
        } catch (Exception $e) {
            $this->error('Erro ao carregar detalhes: ' . $e->getMessage());
        }
    }

    public function conferir(): void
    {
        try {
            $id = (int) $this->request->post('id');
            if (!$id) {
                $this->error('ID da venda não informado');
                return;
            }

            $companyId = $this->getCompanyId();
            $venda = $this->buscarVenda($id);

            if (!$venda) {
                $this->error('Venda não encontrada');
                return;
            }

            $stmt = $this->db->prepare("
                UPDATE vendas
                SET conferido = 1,
                    conferido_por = :usuario,
                    conferido_em = NOW(),
                    status = :novo_status,
                    updated_at = NOW()
                WHERE id = :id AND company_id = :company_id
                  AND modulo_origem = 'venda'
            ");
            $stmt->execute([
                'usuario' => $this->getUserId(),
                'novo_status' => 'finalizado',
                'id' => $id,
                'company_id' => $companyId
            ]);

            $this->logActivity('expedicao_conferencia', 'vendas', $id, [
                'conferido' => true,
                'status_final' => 'finalizado'
            ]);

            $this->success('Conferência registrada e venda finalizada', [
                'redirect' => '/expedicao'
            ]);
        } catch (Exception $e) {
            $this->error('Erro ao registrar conferência: ' . $e->getMessage());
        }
    }

    public function emitirNfe(): void
    {
        $controller = new VendasController($this->request, $this->response);
        $controller->emitirNfe();
    }

    public function despachar(): void
    {
        try {
            $id = (int) $this->request->post('id');
            if (!$id) {
                $this->error('ID da venda não informado');
                return;
            }

            $companyId = $this->getCompanyId();
            $venda = $this->buscarVenda($id);

            if (!$venda) {
                $this->error('Venda não encontrada');
                return;
            }

            $transportadora = trim((string) $this->request->post('transportadora'));
            $rastreio = trim((string) $this->request->post('rastreio'));
            $volumes = (int) ($this->request->post('volumes') ?? 0);
            $responsavel = trim((string) $this->request->post('responsavel'));
            $dataDespacho = $this->request->post('data_despacho');
            $observacoes = trim((string) $this->request->post('observacoes'));

            $stmt = $this->db->prepare("
                UPDATE vendas SET
                    dispatch_transportadora = :transportadora,
                    dispatch_rastreio = :rastreio,
                    dispatch_volumes = :volumes,
                    dispatch_responsavel = :responsavel,
                    dispatch_data = :data_despacho,
                    dispatch_observacoes = :observacoes,
                    updated_at = NOW()
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute([
                'transportadora' => $transportadora ?: null,
                'rastreio' => $rastreio ?: null,
                'volumes' => $volumes > 0 ? $volumes : null,
                'responsavel' => $responsavel ?: null,
                'data_despacho' => !empty($dataDespacho) ? $dataDespacho : date('Y-m-d H:i:s'),
                'observacoes' => $observacoes ?: null,
                'id' => $id,
                'company_id' => $companyId
            ]);

            $this->logActivity('expedicao_despacho', 'vendas', $id, [
                'transportadora' => $transportadora,
                'rastreio' => $rastreio,
                'volumes' => $volumes
            ]);

            $this->success('Despacho registrado com sucesso');
        } catch (Exception $e) {
            $this->error('Erro ao registrar despacho: ' . $e->getMessage());
        }
    }

    public function buscarItens(): void
    {
        $controller = new VendasController($this->request, $this->response);
        $controller->buscarItens();
    }

    private function carregarStatusExpedicao(int $companyId): array
    {
        try {
            $placeholders = implode(',', array_fill(0, count($this->allowedStatuses), '?'));
            $sql = "
                SELECT codigo, nome, cor, icone
                FROM modulo_status
                WHERE company_id = ? AND modulo = 'vendas' AND codigo IN ($placeholders)
                ORDER BY ordem ASC
            ";
            $stmt = $this->db->prepare($sql);
            $params = array_merge([$companyId], $this->allowedStatuses);
            $stmt->execute($params);
            $status = $stmt->fetchAll();

            if (!empty($status)) {
                return $status;
            }
        } catch (Exception $e) {
            error_log("Erro ao carregar status de expedição: " . $e->getMessage());
        }

        // Fallback padrão
        return [
            ['codigo' => 'pendente', 'nome' => 'Pendente'],
            ['codigo' => 'realizado', 'nome' => 'Realizado'],
            ['codigo' => 'faturamento', 'nome' => 'Faturamento'],
            ['codigo' => 'expedicao', 'nome' => 'Expedição'],
            ['codigo' => 'finalizado', 'nome' => 'Finalizado'],
        ];
    }

    private function carregarClientes(int $companyId): array
    {
        try {
            $stmt = $this->db->prepare("
                SELECT id, name
                FROM pessoas
                WHERE company_id = :company_id
                  AND type IN ('cliente', 'ambos')
                  AND is_active = 1
                ORDER BY name ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            return $stmt->fetchAll() ?: [];
        } catch (Exception $e) {
            error_log("Erro ao carregar clientes para expedição: " . $e->getMessage());
            return [];
        }
    }

    private function buscarVenda(int $id): ?array
    {
        $stmt = $this->db->prepare("
            SELECT
                v.*,
                p.id AS customer_id,
                p.name AS customer_name,
                u.name AS vendor_name
            FROM vendas v
            LEFT JOIN pessoas p ON v.customer_id = p.id
            LEFT JOIN users u ON v.vendor_id = u.id
            WHERE v.id = :id AND v.company_id = :company_id
        ");
        $stmt->execute([
            'id' => $id,
            'company_id' => $this->getCompanyId()
        ]);
        return $stmt->fetch() ?: null;
    }

    private function buscarVendaPorNumero(string $saleNumber): ?array
    {
        $stmt = $this->db->prepare("
            SELECT
                v.*,
                p.id AS customer_id,
                p.name AS customer_name,
                u.name AS vendor_name
            FROM vendas v
            LEFT JOIN pessoas p ON v.customer_id = p.id
            LEFT JOIN users u ON v.vendor_id = u.id
            WHERE v.sale_number = :sale_number
              AND v.company_id = :company_id
        ");
        $stmt->execute([
            'sale_number' => $saleNumber,
            'company_id' => $this->getCompanyId()
        ]);
        return $stmt->fetch() ?: null;
    }
}

