<?php
/**
 * Classe para gerenciar logs de auditoria
 * 
 * Uso:
 * AuditoriaLog::registrar('login', [
 *     'cdpessoa' => 5,
 *     'cdempresa' => 2,
 *     'resultado' => 'sucesso'
 * ]);
 */

class AuditoriaLog {
    private static $pdo = null;

    /**
     * Configurar PDO (chamar na inicialização)
     */
    public static function setPDO($pdo) {
        self::$pdo = $pdo;
    }

    /**
     * Obter IP do cliente
     */
    private static function getIP() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $ip = trim($ips[0]);
        } else {
            $ip = $_SERVER['REMOTE_ADDR'] ?? 'desconhecido';
        }
        return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : 'desconhecido';
    }

    /**
     * Obter User Agent
     */
    private static function getUserAgent() {
        return $_SERVER['HTTP_USER_AGENT'] ?? 'desconhecido';
    }

    /**
     * Registrar uma ação no log
     * 
     * @param string $tipo_acao     tipo da ação (login, logout, alteracao, etc)
     * @param array $dados          dados a registrar
     *                              - cdpessoa (opcional)
     *                              - cdempresa (opcional)
     *                              - resultado (sucesso, falha, aviso, bloqueado)
     *                              - descricao (texto livre)
     *                              - dados_adicionais (dados extras em JSON)
     */
    public static function registrar($tipo_acao, $dados = []) {
        if (self::$pdo === null) {
            error_log("AuditoriaLog: PDO não configurado");
            return false;
        }

        try {
            $cdpessoa = isset($dados['cdpessoa']) ? (int)$dados['cdpessoa'] : null;
            $cdempresa = isset($dados['cdempresa']) ? (int)$dados['cdempresa'] : null;
            $resultado = $dados['resultado'] ?? 'sucesso';
            $descricao = $dados['descricao'] ?? '';
            $dados_adicionais = $dados['dados_adicionais'] ?? [];

            // Construir dados JSON
            $dados_json = [
                'timestamp' => date('Y-m-d H:i:s'),
                'browser' => self::getUserAgent(),
                'acao' => $tipo_acao
            ];

            // Adicionar dados extras
            if (!empty($dados_adicionais)) {
                $dados_json = array_merge($dados_json, $dados_adicionais);
            }

            $sql = "
                INSERT INTO back.auditoria_log 
                (tipo_acao, cdpessoa, cdempresa, ip_address, user_agent, resultado, descricao, dados_json, dthcriacao)
                VALUES 
                (:tipo_acao, :cdpessoa, :cdempresa, :ip_address, :user_agent, :resultado, :descricao, :dados_json, NOW())
            ";

            $stmt = self::$pdo->prepare($sql);
            $stmt->execute([
                ':tipo_acao' => $tipo_acao,
                ':cdpessoa' => $cdpessoa,
                ':cdempresa' => $cdempresa,
                ':ip_address' => self::getIP(),
                ':user_agent' => self::getUserAgent(),
                ':resultado' => $resultado,
                ':descricao' => $descricao,
                ':dados_json' => json_encode($dados_json, JSON_UNESCAPED_UNICODE)
            ]);

            return true;

        } catch (Exception $e) {
            error_log("AuditoriaLog::registrar erro: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Obter logs filtrados
     * 
     * @param array $filtros
     *      - tipo_acao (string)
     *      - cdpessoa (int)
     *      - cdempresa (int)
     *      - resultado (string)
     *      - data_inicio (YYYY-MM-DD)
     *      - data_fim (YYYY-MM-DD)
     *      - limit (int, default 100)
     *      - offset (int, default 0)
     */
    public static function obter($filtros = []) {
        if (self::$pdo === null) {
            return [];
        }

        try {
            $where = [];
            $params = [];

            if (!empty($filtros['tipo_acao'])) {
                $where[] = "tipo_acao = :tipo_acao";
                $params[':tipo_acao'] = $filtros['tipo_acao'];
            }

            if (!empty($filtros['cdpessoa'])) {
                $where[] = "cdpessoa = :cdpessoa";
                $params[':cdpessoa'] = (int)$filtros['cdpessoa'];
            }

            if (!empty($filtros['cdempresa'])) {
                $where[] = "cdempresa = :cdempresa";
                $params[':cdempresa'] = (int)$filtros['cdempresa'];
            }

            if (!empty($filtros['resultado'])) {
                $where[] = "resultado = :resultado";
                $params[':resultado'] = $filtros['resultado'];
            }

            if (!empty($filtros['data_inicio'])) {
                $where[] = "dthcriacao >= :data_inicio::timestamp";
                $params[':data_inicio'] = $filtros['data_inicio'];
            }

            if (!empty($filtros['data_fim'])) {
                $where[] = "dthcriacao <= :data_fim::timestamp + interval '1 day'";
                $params[':data_fim'] = $filtros['data_fim'];
            }

            $whereSql = !empty($where) ? "WHERE " . implode(" AND ", $where) : "";

            $limit = (int)($filtros['limit'] ?? 100);
            $offset = (int)($filtros['offset'] ?? 0);

            $sql = "
                SELECT 
                    cdlog, tipo_acao, cdpessoa, cdempresa, ip_address, resultado, 
                    descricao, dados_json, dthcriacao,
                    CASE WHEN cdpessoa IS NOT NULL THEN (SELECT dspessoa FROM back.pessoa WHERE cdpessoa = auditoria_log.cdpessoa) ELSE NULL END as dspessoa,
                    CASE WHEN cdempresa IS NOT NULL THEN (SELECT dsempresa FROM back.empresa WHERE cdempresa = auditoria_log.cdempresa) ELSE NULL END as dsempresa
                FROM back.auditoria_log
                $whereSql
                ORDER BY dthcriacao DESC
                LIMIT $limit OFFSET $offset
            ";

            $stmt = self::$pdo->prepare($sql);
            foreach ($params as $k => $v) {
                $stmt->bindValue($k, $v);
            }
            $stmt->execute();

            return $stmt->fetchAll(PDO::FETCH_ASSOC);

        } catch (Exception $e) {
            error_log("AuditoriaLog::obter erro: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Contar logs com filtros
     */
    public static function contar($filtros = []) {
        if (self::$pdo === null) {
            return 0;
        }

        try {
            $where = [];
            $params = [];

            if (!empty($filtros['tipo_acao'])) {
                $where[] = "tipo_acao = :tipo_acao";
                $params[':tipo_acao'] = $filtros['tipo_acao'];
            }

            if (!empty($filtros['cdpessoa'])) {
                $where[] = "cdpessoa = :cdpessoa";
                $params[':cdpessoa'] = (int)$filtros['cdpessoa'];
            }

            if (!empty($filtros['cdempresa'])) {
                $where[] = "cdempresa = :cdempresa";
                $params[':cdempresa'] = (int)$filtros['cdempresa'];
            }

            $whereSql = !empty($where) ? "WHERE " . implode(" AND ", $where) : "";

            $sql = "SELECT COUNT(*) FROM back.auditoria_log $whereSql";

            $stmt = self::$pdo->prepare($sql);
            foreach ($params as $k => $v) {
                $stmt->bindValue($k, $v);
            }
            $stmt->execute();

            return (int)$stmt->fetchColumn();

        } catch (Exception $e) {
            error_log("AuditoriaLog::contar erro: " . $e->getMessage());
            return 0;
        }
    }
}
?>
