<?php
// ============================================================
// auditoria.php
// Classe para registrar operações de auditoria
// Uso: Auditoria::registrar('acoes', 'INSERT', 1, null, $dados, 'Ação criada');
// ============================================================

class Auditoria {
    private static $db = null;
    private static $usuario_id = null;
    private static $usuario_nome = null;
    private static $usuario_perfil = null;

    /**
     * Inicializar auditoria com dados do usuário
     * @param PDO $db Conexão com banco de dados
     * @param int $usuario_id ID do usuário
     * @param string $usuario_nome Nome do usuário
     * @param string $usuario_perfil Perfil do usuário (admin, diretor, gestor, tecnico)
     */
    public static function inicializar($db, $usuario_id, $usuario_nome, $usuario_perfil) {
        self::$db = $db;
        self::$usuario_id = $usuario_id;
        self::$usuario_nome = $usuario_nome;
        self::$usuario_perfil = $usuario_perfil;
    }

    /**
     * Registrar operação de auditoria
     * @param string $tabela Nome da tabela
     * @param string $operacao INSERT, UPDATE ou DELETE
     * @param int $registro_id ID do registro afetado
     * @param array $dados_antes Dados antes da operação (para UPDATE/DELETE)
     * @param array $dados_depois Dados depois da operação (para INSERT/UPDATE)
     * @param string $descricao Descrição da operação
     * @return bool True se registrado com sucesso
     */
    public static function registrar($tabela, $operacao, $registro_id, $dados_antes = null, $dados_depois = null, $descricao = '') {
        // Se não foi inicializado, retornar silenciosamente
        if (self::$db === null) {
            return false;
        }

        try {
            $ip_address = self::obter_ip();
            $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';

            $sql = "INSERT INTO auditoria (
                usuario_id, usuario_nome, usuario_perfil, tabela, operacao,
                registro_id, dados_antes, dados_depois, descricao, ip_address, user_agent
            ) VALUES (
                :usuario_id, :usuario_nome, :usuario_perfil, :tabela, :operacao,
                :registro_id, :dados_antes, :dados_depois, :descricao, :ip_address, :user_agent
            )";

            $stmt = self::$db->prepare($sql);
            $stmt->execute([
                ':usuario_id' => self::$usuario_id,
                ':usuario_nome' => self::$usuario_nome,
                ':usuario_perfil' => self::$usuario_perfil,
                ':tabela' => $tabela,
                ':operacao' => strtoupper($operacao),
                ':registro_id' => $registro_id,
                ':dados_antes' => $dados_antes ? json_encode($dados_antes) : null,
                ':dados_depois' => $dados_depois ? json_encode($dados_depois) : null,
                ':descricao' => $descricao,
                ':ip_address' => $ip_address,
                ':user_agent' => substr($user_agent, 0, 255)
            ]);

            return true;
        } catch (Exception $e) {
            // Log silencioso — não quebra a operação principal
            error_log('Erro ao registrar auditoria: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Registrar criação de registro (INSERT)
     * @param string $tabela Nome da tabela
     * @param int $registro_id ID do registro criado
     * @param array $dados Dados do registro
     * @param string $descricao Descrição
     */
    public static function criar($tabela, $registro_id, $dados, $descricao = '') {
        self::registrar($tabela, 'INSERT', $registro_id, null, $dados, $descricao);
    }

    /**
     * Registrar atualização de registro (UPDATE)
     * @param string $tabela Nome da tabela
     * @param int $registro_id ID do registro
     * @param array $dados_antes Dados antes
     * @param array $dados_depois Dados depois
     * @param string $descricao Descrição
     */
    public static function atualizar($tabela, $registro_id, $dados_antes, $dados_depois, $descricao = '') {
        self::registrar($tabela, 'UPDATE', $registro_id, $dados_antes, $dados_depois, $descricao);
    }

    /**
     * Registrar exclusão de registro (DELETE)
     * @param string $tabela Nome da tabela
     * @param int $registro_id ID do registro
     * @param array $dados Dados do registro deletado
     * @param string $descricao Descrição
     */
    public static function deletar($tabela, $registro_id, $dados, $descricao = '') {
        self::registrar($tabela, 'DELETE', $registro_id, $dados, null, $descricao);
    }

    /**
     * Obter histórico de auditoria de um registro
     * @param string $tabela Nome da tabela
     * @param int $registro_id ID do registro
     * @return array Histórico de operações
     */
    public static function obter_historico($tabela, $registro_id) {
        if (self::$db === null) {
            return [];
        }

        try {
            $sql = "SELECT * FROM auditoria
                    WHERE tabela = :tabela AND registro_id = :registro_id
                    ORDER BY criado_em DESC";
            $stmt = self::$db->prepare($sql);
            $stmt->execute([
                ':tabela' => $tabela,
                ':registro_id' => $registro_id
            ]);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log('Erro ao obter histórico: ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Obter auditoria de um usuário
     * @param int $usuario_id ID do usuário
     * @param int $limite Número de registros
     * @return array Operações do usuário
     */
    public static function obter_por_usuario($usuario_id, $limite = 100) {
        if (self::$db === null) {
            return [];
        }

        try {
            $sql = "SELECT * FROM auditoria
                    WHERE usuario_id = :usuario_id
                    ORDER BY criado_em DESC
                    LIMIT :limite";
            $stmt = self::$db->prepare($sql);
            $stmt->bindValue(':usuario_id', $usuario_id, PDO::PARAM_INT);
            $stmt->bindValue(':limite', $limite, PDO::PARAM_INT);
            $stmt->execute();
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log('Erro ao obter auditoria por usuário: ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Obter auditoria por período
     * @param string $data_inicio Data inicial (YYYY-MM-DD)
     * @param string $data_fim Data final (YYYY-MM-DD)
     * @param string $tabela Filtrar por tabela (opcional)
     * @return array Operações no período
     */
    public static function obter_por_periodo($data_inicio, $data_fim, $tabela = null) {
        if (self::$db === null) {
            return [];
        }

        try {
            $sql = "SELECT * FROM auditoria
                    WHERE DATE(criado_em) BETWEEN :data_inicio AND :data_fim";
            $params = [
                ':data_inicio' => $data_inicio,
                ':data_fim' => $data_fim
            ];

            if ($tabela) {
                $sql .= " AND tabela = :tabela";
                $params[':tabela'] = $tabela;
            }

            $sql .= " ORDER BY criado_em DESC";
            $stmt = self::$db->prepare($sql);
            $stmt->execute($params);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log('Erro ao obter auditoria por período: ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Obter IP do cliente
     * @return string IP address
     */
    private static function obter_ip() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
        } else {
            return $_SERVER['REMOTE_ADDR'] ?? 'DESCONHECIDO';
        }
    }

    /**
     * Limpar auditoria antiga (mais de 90 dias)
     * @param int $dias Número de dias para manter
     * @return int Número de registros deletados
     */
    public static function limpar_antiga($dias = 90) {
        if (self::$db === null) {
            return 0;
        }

        try {
            $sql = "DELETE FROM auditoria WHERE criado_em < DATE_SUB(NOW(), INTERVAL :dias DAY)";
            $stmt = self::$db->prepare($sql);
            $stmt->bindValue(':dias', $dias, PDO::PARAM_INT);
            $stmt->execute();
            return $stmt->rowCount();
        } catch (Exception $e) {
            error_log('Erro ao limpar auditoria: ' . $e->getMessage());
            return 0;
        }
    }
}

?>
