<?php

declare(strict_types=1);

namespace App\Controllers;

use Exception;
use App\Helpers\UrlHelper;

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

        try {
            $companyId = $this->getCompanyId();

            // Paginação
            $perPage = 50;
            $page = max(1, (int) ($this->request->get('page') ?? 1));
            $offset = ($page - 1) * $perPage;

            // Contar total de centros
            $stmtCount = $this->db->prepare("
                SELECT COUNT(*) as total
                FROM centro_custos cc
                WHERE cc.company_id = :company_id
            ");
            $stmtCount->execute(['company_id' => $companyId]);
            $total = (int) $stmtCount->fetch()['total'];
            $totalPages = max(1, (int) ceil($total / $perPage));

            // Buscar centros (paginado)
            $stmt = $this->db->prepare("
                SELECT cc.*,
                       parent.name as parent_name
                FROM centro_custos cc
                LEFT JOIN centro_custos parent ON cc.parent_id = parent.id
                WHERE cc.company_id = :company_id
                ORDER BY cc.code ASC
                LIMIT :limit OFFSET :offset
            ");
            $stmt->bindValue(':company_id', $companyId, \PDO::PARAM_INT);
            $stmt->bindValue(':limit', $perPage, \PDO::PARAM_INT);
            $stmt->bindValue(':offset', $offset, \PDO::PARAM_INT);
            $stmt->execute();
            $centros = $stmt->fetchAll();

            $this->view('centro-custos/index', [
                'centros' => $centros,
                'pageTitle' => 'Centro de Custos',
                'activeMenu' => 'centro-custos',
                'page' => $page,
                'perPage' => $perPage,
                'total' => $total,
                'totalPages' => $totalPages
            ]);

        } catch (Exception $e) {
            error_log("Erro ao carregar centro de custos: " . $e->getMessage());
            $this->error('Erro ao carregar centro de custos');
        }
    }

    public function create(): void
    {
        $centros = $this->getCentrosPai();

        $this->view('centro-custos/create', [
            'centros' => $centros,
            'pageTitle' => 'Novo Centro de Custo',
            'activeMenu' => 'centro-custos'
        ]);
    }

    public function store(): void
    {
        // Verificar permissão de criação
        if (!$this->canCreate('centro-custos')) {
            $this->response->forbidden('Você não tem permissão para criar centro de custos.');
            return;
        }

        try {
            $companyId = $this->getCompanyId();

            $data = [
                'company_id' => $companyId,
                'parent_id' => $this->request->post('parent_id') ?: null,
                'code' => $this->request->post('code'),
                'name' => $this->request->post('name'),
                'notes' => $this->request->post('notes') ?: null,
                'is_active' => 1,
            ];

            $this->db->beginTransaction();

            $stmt = $this->db->prepare("
                INSERT INTO centro_custos (company_id, parent_id, code, name, notes, is_active, created_at, updated_at)
                VALUES (:company_id, :parent_id, :code, :name, :notes, :is_active, NOW(), NOW())
            ");
            $stmt->execute($data);
            $centroId = (int) $this->db->lastInsertId();

            $this->logActivity('create', 'centro_custos', $centroId, $data);
            $this->db->commit();

            $this->success('Centro de custo criado com sucesso', [
                'id' => $centroId,
                'redirect' => UrlHelper::url('/centro-custos')
            ]);

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao criar centro de custo: " . $e->getMessage());
            error_log("Stack: " . $e->getTraceAsString());
            $this->error('Erro ao criar centro de custo: ' . $e->getMessage());
        }
    }

    public function edit(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('centro-custos')) {
            $this->response->forbidden('Você não tem permissão para editar centro de custos.');
            return;
        }

        try {
            $id = (int) $this->request->get('id');
            $centro = $this->getCentro($id);

            if (!$centro) {
                $this->response->notFound('Centro de custo não encontrado');
                return;
            }

            $centros = $this->getCentrosPai($id);

            $this->view('centro-custos/edit', [
                'centro' => $centro,
                'centros' => $centros,
                'pageTitle' => 'Editar Centro de Custo',
                'activeMenu' => 'centro-custos'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao editar centro de custo: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

    public function update(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('centro-custos')) {
            $this->response->forbidden('Você não tem permissão para editar centro de custos.');
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            $centro = $this->getCentro($id);

            if (!$centro) {
                $this->error('Centro de custo não encontrado');
                return;
            }

            $data = [
                'parent_id' => $this->request->post('parent_id') ?: null,
                'code' => $this->request->post('code'),
                'name' => $this->request->post('name'),
                'notes' => $this->request->post('notes') ?: null,
                'is_active' => $this->request->post('is_active') ? 1 : 0,
                'id' => $id,
                'company_id' => $this->getCompanyId()
            ];

            $this->db->beginTransaction();

            $stmt = $this->db->prepare("
                UPDATE centro_custos SET
                    parent_id = :parent_id,
                    code = :code,
                    name = :name,
                    notes = :notes,
                    is_active = :is_active,
                    updated_at = NOW()
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute($data);

            $this->logActivity('update', 'centro_custos', $id, $data);
            $this->db->commit();

            $this->success('Centro de custo atualizado com sucesso', [
                'redirect' => UrlHelper::url('/centro-custos')
            ]);

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao atualizar centro de custo: " . $e->getMessage());
            error_log("Stack: " . $e->getTraceAsString());
            $this->error('Erro ao atualizar centro de custo: ' . $e->getMessage());
        }
    }

    public function delete(): void
    {
        // Verificar permissão de exclusão
        if (!$this->canDelete('centro-custos')) {
            $this->response->forbidden('Você não tem permissão para excluir centro de custos.');
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            $centro = $this->getCentro($id);

            if (!$centro) {
                $this->error('Centro de custo não encontrado');
                return;
            }

            $companyId = $this->getCompanyId();

            // Verificar se há centros de custo filhos
            $stmt = $this->db->prepare("SELECT COUNT(*) as total FROM centro_custos WHERE parent_id = :id AND company_id = :company_id");
            $stmt->execute(['id' => $id, 'company_id' => $companyId]);
            $filhos = $stmt->fetch();

            if ($filhos && $filhos['total'] > 0) {
                $this->error('Não é possível excluir este centro de custo pois existem ' . $filhos['total'] . ' centro(s) de custo filho(s) vinculado(s). Remova ou altere os centros filhos primeiro.');
                return;
            }

            // Verificar se há movimentações relacionadas
            try {
                $stmt = $this->db->prepare("SELECT COUNT(*) as total FROM movimentacao_centro_custos WHERE centro_id = :id AND company_id = :company_id");
                $stmt->execute(['id' => $id, 'company_id' => $companyId]);
                $movimentacoes = $stmt->fetch();

                if ($movimentacoes && $movimentacoes['total'] > 0) {
                    $this->error('Não é possível excluir este centro de custo pois existem ' . $movimentacoes['total'] . ' movimentação(ões) financeira(s) vinculada(s). O centro de custo está sendo utilizado em transações.');
                    return;
                }
            } catch (Exception $e) {
                // Tabela pode não existir em algumas instalações, ignorar
                error_log("Aviso: Tabela movimentacao_centro_custos não encontrada ou erro ao verificar: " . $e->getMessage());
            }

            // Verificar se há compras relacionadas (informação adicional)
            try {
                $stmt = $this->db->prepare("SELECT COUNT(*) as total FROM compras_centro_custos WHERE centro_id = :id");
                $stmt->execute(['id' => $id]);
                $compras = $stmt->fetch();

                if ($compras && $compras['total'] > 0) {
                    // Compras tem CASCADE, mas informamos ao usuário
                    error_log("Aviso: Excluindo centro de custo com {$compras['total']} compra(s) relacionada(s) (serão excluídas automaticamente)");
                }
            } catch (Exception $e) {
                // Tabela pode não existir em algumas instalações, ignorar
                error_log("Aviso: Tabela compras_centro_custos não encontrada ou erro ao verificar: " . $e->getMessage());
            }

            $this->db->beginTransaction();

            $stmt = $this->db->prepare("DELETE FROM centro_custos WHERE id = :id AND company_id = :company_id");
            $stmt->execute(['id' => $id, 'company_id' => $companyId]);

            $this->logActivity('delete', 'centro_custos', $id, $centro);
            $this->db->commit();

            $this->success('Centro de custo excluído com sucesso');

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao excluir centro de custo: " . $e->getMessage());
            error_log("Stack: " . $e->getTraceAsString());

            // Verificar se é erro de constraint de foreign key
            if (strpos($e->getMessage(), '1451') !== false || strpos($e->getMessage(), 'Integrity constraint violation') !== false) {
                $this->error('Não é possível excluir este centro de custo pois ele está sendo utilizado em outras operações do sistema. Remova as dependências primeiro.');
            } else {
                $this->error('Erro ao excluir centro de custo: ' . $e->getMessage());
            }
        }
    }

    private function getCentro(int $id): ?array
    {
        $stmt = $this->db->prepare("SELECT * FROM centro_custos WHERE id = :id AND company_id = :company_id");
        $stmt->execute(['id' => $id, 'company_id' => $this->getCompanyId()]);
        return $stmt->fetch() ?: null;
    }

    private function getCentrosPai(?int $excludeId = null): array
    {
        $query = "SELECT id, code, name FROM centro_custos WHERE company_id = :company_id";
        $params = ['company_id' => $this->getCompanyId()];

        if ($excludeId) {
            $query .= " AND id != :exclude_id";
            $params['exclude_id'] = $excludeId;
        }

        $query .= " ORDER BY code ASC";

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

