from flask import Blueprint, request, jsonify, current_app
import jwt
from datetime import datetime, timedelta
import re
import ldap3
from ldap3.core.exceptions import LDAPSocketOpenError, LDAPException
from functools import wraps
import logging
from flask_mysqldb import MySQL

# Configuração de logging para depuração
logging.basicConfig(level=logging.DEBUG)

auth = Blueprint('auth', __name__)
mysql = MySQL()

# Decorador para validar o token JWT
def token_required(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        token = request.headers.get('x-access-token')
        if not token:
            return jsonify({'msg': 'Token é necessário!'}), 401

        try:
            data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"])
        except jwt.ExpiredSignatureError:
            return jsonify({'msg': 'Token expirado!'}), 401
        except jwt.InvalidTokenError:
            return jsonify({'msg': 'Token inválido!'}), 401

        return f(data, *args, **kwargs)

    return wrapper


# Validação de SQL Injection
def is_valid_input(input_str):
    sql_injection_pattern = r"(--|\b(SELECT|UNION|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER)\b|;|'|\")"
    return not re.search(sql_injection_pattern, input_str, re.IGNORECASE)


# Validação de e-mail
def is_valid_email(email):
    return re.match(r"[^@]+@[^@]+\.[^@]+", email)


# Rota de login
@auth.route('/login', methods=['POST'])
def login():
    data = request.get_json()

    username_full = data.get('username')
    password = data.get('password')

    if not username_full or not password:
        return jsonify({'msg': 'Usuário e senha são obrigatórios.'}), 400

    if not is_valid_input(username_full) or not is_valid_input(password):
        return jsonify({'msg': 'Solicitação rejeitada devido a padrões maliciosos.'}), 422

    if not is_valid_email(username_full):
        return jsonify({'msg': 'Formato de e-mail inválido'}), 400

    # Separar nome de usuário e domínio
    try:
        username, domain = username_full.split('@')
    except ValueError:
        return jsonify({'msg': 'Formato de usuário inválido. Use "usuario@dominio.com".'}), 400

    # Verificar se o usuário está associado à empresa no MySQL
    try:
        with mysql.connection.cursor() as cur:
            cur.execute("SELECT fk_id_empresa, dominio FROM usuarios WHERE usuario = %s AND dominio = %s", (username, domain))
            result = cur.fetchone()

        if not result:
            return jsonify({'msg': 'Usuário não associado à empresa'}), 404
    except Exception as e:
        logging.error(f"Erro no banco de dados: {str(e)}")
        return jsonify({'msg': 'Erro no banco de dados'}), 500

    # Autenticação LDAP usando domínio extraído
    ldap_server = f'ldap://{domain}:389'
    ldap_user = f'{domain}\\{username}'

    try:
        server = ldap3.Server(ldap_server, get_info=ldap3.ALL)
        conn = ldap3.Connection(
            server,
            user=username_full,
            password=password,
            authentication=ldap3.SIMPLE # Sempre utilizar o modo SIMPLE
        )

        if conn.bind():
            token = jwt.encode({
                'user': username_full,
                'domain': domain,  # Incluindo o domínio no payload
                'exp': datetime.utcnow() + timedelta(hours=1)
            }, current_app.config['SECRET_KEY'], algorithm="HS256")

            conn.unbind()
            logging.info(f"Login bem-sucedido para usuário: {username_full}")
            return jsonify({'msg': 'Login bem-sucedido', 'token': token, 'domain': domain}), 200
        else:
            conn.unbind()
            logging.warning(f"Falha na autenticação LDAP para o usuário: {username_full}")
            return jsonify({'msg': 'Falha na autenticação LDAP. Verifique credenciais.'}), 401

    except LDAPSocketOpenError:
        logging.error("Erro de conexão com o servidor LDAP.")
        return jsonify({'msg': 'Não foi possível conectar ao servidor LDAP. Verifique o IP e a porta.'}), 503
    except LDAPException as e:
        logging.error(f"Erro LDAP: {str(e)}")
        return jsonify({'msg': 'Erro durante a autenticação no servidor LDAP.'}), 500
    except Exception as e:
        logging.error(f"Erro inesperado: {str(e)}")
        return jsonify({'msg': 'Erro inesperado durante a autenticação.'}), 500
