<?php
class Auth
{
    private $conn;
    private $secretKey;

    public function __construct($db)
    {
        $this->conn = $db;
        $this->secretKey = 'tu_clave_secreta_muy_segura_2024'; // En producción usar variable de entorno
    }

    public function generarJWT($usuario)
    {
        $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);

        // Si el array ya contiene los campos del payload (como iat, exp, etc.), usarlo directamente
        if (isset($usuario['iat']) && isset($usuario['exp'])) {
            // Es un payload completo, usarlo tal cual
            $payload = json_encode($usuario);
        } else {
            // Es un usuario web, construir el payload tradicional
            $payload = json_encode([
                'iss' => 'api_rutas',
                'sub' => $usuario['id'] ?? '',
                'username' => $usuario['username'] ?? '',
                'email' => $usuario['email'],
                'nombre' => $usuario['nombre'],
                'apellido' => $usuario['apellido'] ?? '',
                'roles' => $usuario['roles'] ?? '',
                'iat' => time(),
                'exp' => time() + (24 * 60 * 60) // 24 horas
            ]);
        }

        $base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
        $base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));

        $signature = hash_hmac('sha256', $base64Header . "." . $base64Payload, $this->secretKey, true);
        $base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

        return $base64Header . "." . $base64Payload . "." . $base64Signature;
    }

    public function verificarJWT($token)
    {
        try {
            $tokenParts = explode('.', $token);

            if (count($tokenParts) !== 3) {
                return false;
            }

            $header = base64_decode(str_replace(['-', '_'], ['+', '/'], $tokenParts[0]));
            $payload = base64_decode(str_replace(['-', '_'], ['+', '/'], $tokenParts[1]));
            $signature = $tokenParts[2];

            $expectedSignature = hash_hmac('sha256', $tokenParts[0] . "." . $tokenParts[1], $this->secretKey, true);
            $expectedSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($expectedSignature));

            if ($signature !== $expectedSignature) {
                return false;
            }

            $payloadData = json_decode($payload, true);

            if ($payloadData['exp'] < time()) {
                return false;
            }

            return $payloadData;
        } catch (Exception $e) {
            error_log("Error verificando JWT: " . $e->getMessage());
            return false;
        }
    }

    public function obtenerUsuarioDeToken($token)
    {
        $payload = $this->verificarJWT($token);

        if (!$payload) {
            return false;
        }

        // Verificar si el usuario sigue activo
        $query = "SELECT id, activo FROM usuarios WHERE id = :id";
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':id', $payload['sub']);
        $stmt->execute();

        $usuario = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$usuario || !$usuario['activo']) {
            return false;
        }

        return $payload;
    }

    public function obtenerTokenDeHeader()
    {
        $headers = getallheaders();

        if (isset($headers['Authorization'])) {
            $authHeader = $headers['Authorization'];
            if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
                return $matches[1];
            }
        }

        return null;
    }

    public function requiereAutenticacion()
    {
        $token = $this->obtenerTokenDeHeader();

        if (!$token) {
            http_response_code(401);
            echo json_encode(['error' => 'Token de acceso requerido']);
            exit();
        }

        $usuario = $this->obtenerUsuarioDeToken($token);

        if (!$usuario) {
            http_response_code(401);
            echo json_encode(['error' => 'Token inválido o expirado']);
            exit();
        }

        return $usuario;
    }

    public function requierePermiso($modulo, $permiso)
    {
        $usuario = $this->requiereAutenticacion();

        $usuarioModel = new Usuario($this->conn);
        $tienePermiso = $usuarioModel->verificarPermiso($usuario['sub'], $modulo, $permiso);

        if (!$tienePermiso) {
            http_response_code(403);
            echo json_encode(['error' => 'No tiene permisos para realizar esta acción']);
            exit();
        }

        return $usuario;
    }
}
