from tzlocal import get_localzone

from functools import wraps

from flask import Blueprint, render_template, abort, request, Flask, current_app, session, redirect, url_for
import os

from modules.WireguardConfiguration import WireguardConfiguration
from modules.DashboardConfig import DashboardConfig

def ResponseObject(status=True, message=None, data=None, status_code = 200) -> Flask.response_class:
    response = Flask.make_response(current_app, {
        "status": status,
        "message": message,
        "data": data
    })
    response.status_code = status_code
    response.content_type = "application/json"
    return response



from modules.DashboardClients import DashboardClients
def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration], dashboardConfig: DashboardConfig, dashboardClients: DashboardClients):
        
    client = Blueprint('client', __name__, template_folder=os.path.abspath("./static/client/dist"))
    prefix = f'{dashboardConfig.GetConfig("Server", "app_prefix")[1]}/client'

    def login_required(f):
        @wraps(f)
        def func(*args, **kwargs):
            if session.get("Email") is None or session.get("TotpVerified") is None or not session.get("TotpVerified") or session.get("Role") != "client":
                return ResponseObject(False, "Unauthorized access.", data=None, status_code=401)
        
            if not dashboardClients.GetClient(session.get("ClientID")):
                session.clear()
                return ResponseObject(False, "Unauthorized access.", data=None, status_code=401)
            
            return f(*args, **kwargs)
        return func
    
    @client.before_request
    def clientBeforeRequest():
        if request.method.lower() == 'options':
            return ResponseObject(True)
    
    @client.post(f'{prefix}/api/signup')
    def ClientAPI_SignUp():
        data = request.json
        status, msg = dashboardClients.SignUp(**data)
        return ResponseObject(status, msg)

    @client.get(f'{prefix}/api/signin/oidc/providers')
    def ClientAPI_SignIn_OIDC_GetProviders():
        _, oidc = dashboardConfig.GetConfig("OIDC", "client_enable")
        if not oidc:
            return ResponseObject(status=False, message="OIDC is disabled")
        
        return ResponseObject(data=dashboardClients.OIDC.GetProviders())
    
    @client.post(f'{prefix}/api/signin/oidc')
    def ClientAPI_SignIn_OIDC():
        _, oidc = dashboardConfig.GetConfig("OIDC", "client_enable")
        if not oidc:
            return ResponseObject(status=False, message="OIDC is disabled")
        
        data = request.json
        status, oidcData = dashboardClients.SignIn_OIDC(**data)
        if not status:
            return ResponseObject(status, oidcData)

        session['Email'] = oidcData.get('email')
        session['Role'] = 'client'
        session['TotpVerified'] = True
        
        return ResponseObject()
    
    @client.post(f'{prefix}/api/signin')
    def ClientAPI_SignIn():
        data = request.json
        status, msg = dashboardClients.SignIn(**data)
        if status:
            session['Email'] = data.get('Email')
            session['Role'] = 'client'
            session['TotpVerified'] = False
        return ResponseObject(status, msg)

    @client.get(f'{prefix}/api/signout')
    def ClientAPI_SignOut():
        if session.get("SignInMethod") == "OIDC":
            dashboardClients.SignOut_OIDC()
        session.clear()
        return ResponseObject(True)
    
    @client.get(f'{prefix}/api/signin/totp')
    def ClientAPI_SignIn_TOTP():
        token = request.args.get('Token', None)
        if not token:
            return ResponseObject(False, "Please provide TOTP token")
        
        status, msg = dashboardClients.SignIn_GetTotp(token)
        return ResponseObject(status, msg)

    @client.post(f'{prefix}/api/signin/totp')
    def ClientAPI_SignIn_ValidateTOTP():
        data = request.json
        token = data.get('Token', None)
        userProvidedTotp = data.get('UserProvidedTOTP', None)
        if not all([token, userProvidedTotp]):
            return ResponseObject(False, "Please fill in all fields")
        status, msg = dashboardClients.SignIn_GetTotp(token, userProvidedTotp)
        if status:
            if session.get('Email') is None:
                return ResponseObject(False, "Sign in status is invalid", status_code=401)
            session['TotpVerified'] = True
            profile = dashboardClients.GetClientProfile(session.get("ClientID"))
            
            return ResponseObject(True, data={
                "Email": session.get('Email'),
                "Profile": profile
            })
        return ResponseObject(status, msg)
    
    @client.get(prefix)
    def ClientIndex():
        return render_template('client.html')
    
    @client.get(f'{prefix}/api/serverInformation')
    def ClientAPI_ServerInformation():
        return ResponseObject(data={
            "ServerTimezone": str(get_localzone())
        })
    
    @client.get(f'{prefix}/api/validateAuthentication')
    @login_required
    def ClientAPI_ValidateAuthentication():
        return ResponseObject(True)
    
    @client.get(f'{prefix}/api/configurations')
    @login_required
    def ClientAPI_Configurations():
        return ResponseObject(True, data=dashboardClients.GetClientAssignedPeers(session['ClientID']))
    
    @client.get(f'{prefix}/api/settings/getClientProfile')
    @login_required
    def ClientAPI_Settings_GetClientProfile():
        return ResponseObject(data={
            "Email": session.get("Email"),
            "SignInMethod": session.get("SignInMethod"),
            "Profile": dashboardClients.GetClientProfile(session.get("ClientID"))
        })
    
    @client.post(f'{prefix}/api/settings/updatePassword')
    @login_required
    def ClientAPI_Settings_UpdatePassword():
        data = request.get_json()
        status, message = dashboardClients.UpdateClientPassword(session['Email'], **data)
    
        return ResponseObject(status, message)
    
    return client