from flask import Flask, render_template, request, redirect, url_for, session, flash, send_file, jsonify
from flask_socketio import SocketIO, join_room, leave_room, emit
from mysql_flask import Mysql
import os
import bcrypt
from dotenv import load_dotenv
import jwt
from functools import wraps
from datetime import datetime, timedelta
from flask_cors import CORS
from removebg import RemoveBG
from imagetotext import ImageToText
from classify_mages import Classify

load_dotenv()

app = Flask(__name__)


config_cors = {
    'origins':['*'],
    'methods':['OPTIONS', 'GET', 'POST'],
    'expose_headers': ['Content-Type', 'Authorization', 'Access-Control-Allow-Origin'],
}

cors = CORS(app, resources={
    r'/*':config_cors
})


app.secret_key = os.getenv("APP_SECRET")
app.config['MYSQL_HOST'] = os.getenv('MYSQL_HOST')
app.config['MYSQL_PORT'] = os.getenv('MYSQL_PORT')
app.config['MYSQL_USER'] = os.getenv('MYSQL_USER')
app.config['MYSQL_PASSWORD'] = os.getenv('MYSQL_PASSWORD')
app.config['MYSQL_DB'] = os.getenv('MYSQL_DB')
app.config['MYSQL_CURSORCLASS'] = 'DictCursor'

mysql = Mysql(app)

socketio = SocketIO(app, cors_allowed_origins="*")


def compare(password, hash):
    # Verificar se a senha corresponde ao hash armazenado
    return bcrypt.checkpw(password.encode('utf-8'), hash.encode('utf-8'))

def getUser(data):
    user = data.get('username')
    password = data.get('password')
    sql = "SELECT * FROM user WHERE username = %s"
    result = mysql.execute_query(sql, (user,), one_result=True, columns=['id', 'nome', 'username', 'password'])
    if result:
        hash = result['password']
        if compare(password, hash):
            return result
        return None
    return None

def gerar_token(user):
    id = user['id']
    nome = user['nome']
    username = user['username']

    expire = datetime.utcnow() + timedelta(days=1)

    payload = {
        'user': {'id':id, 'nome': nome, 'username': username},
        'exp': expire
    }

    token = jwt.encode(payload, app.config['SECRET_KEY'], algorithm="HS256")
    return token
    

def validate_token(token):
    try:
        data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
        request.user_info = data.get('user')
        return 'Token válido'
    except jwt.ExpiredSignatureError as e:
        return f'Forbidden: Access is denied. {e}'
    except jwt.InvalidTokenError as e:
        return f'Forbidden: Access is denied. {e}'

def guard(f):
    @wraps(f)
    def decorador(*args, **kwargs):
        token_access = request.headers.get('Authorization')
        if not token_access:
            return jsonify({'msg': 'Forbidden: Access is denied.'}), 403
        try:
            token = token_access.split()
            validid_token = validate_token(token[1])
            if validid_token == 'Token válido':
                pass
            else:
                return jsonify({'msg': validid_token}), 403
        except Exception as e:
            return jsonify({'msg': f'Forbidden: Access is denied.'}), 403
        return f(*args, **kwargs)  # Corrija a indentação desta linha
    return decorador



@app.route('/api/')
@guard
def index():
    user_info = request.user_info
    return jsonify({'msg': f'Usuário logado: {user_info}'})

@app.route('/api/login', methods=['POST'])
def login():
    data = request.get_json()
    user = getUser(data)
    if user == None:
        response = jsonify({"message": "Unauthorized: Access is denied due to invalid credentials."})
        response.status_code = 401
        return response
    return jsonify({'token': gerar_token(user)})



@app.route('/tmp_nobg/<filename>')
@guard
def serve_image(filename):
    return send_file(f'./tmp_nobg/{filename}', mimetype='image/png')

def guardSocket(f):
    @wraps(f)
    def decorador(*args, **kwargs):
        token = request.args.get('token')

        return f(*args, **kwargs)  # Corrija a indentação desta linha
    return decorador

@socketio.on('removebg')
@guardSocket
def removebg(data):

    removebg = RemoveBG()
    imagenobg = removebg.init(data)

  
    data_nobg = {'data_nobg': imagenobg}
    # Envie a mensagem apenas para a sala do usuário específico
    emit('removebg_response', data_nobg)

@socketio.on('removetmp')
@guardSocket
def removebg(data):

    caminho = f".{data['data']}"
    if os.path.exists(caminho):
        os.remove(caminho)

@socketio.on('extractText')
@guardSocket
def imageToText(data):

    imageToText = ImageToText()
    image_path = imageToText.init(data)
    text = imageToText.extractText(image_path)

    data_text = {'text': text}

    emit('extractText_response', data_text)

@socketio.on('linkcertoclassify')
def classifyLinkCertoImg(data):
    classify = Classify('./models/linkcerto/model.h5', './models/linkcerto/class_mapping.json')
    result = classify.init(data)
    result_res = {'classify': result}
    emit('classify_response', result_res)
    

if __name__ == "__main__":
    socketio.run(app, host='0.0.0.0', port=30000, debug=True, allow_unsafe_werkzeug=True)