import os
import random
import string
from typing import List
import psycopg2
from psycopg2 import sql
from datetime import datetime, timedelta,timezone
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64
import json
from datetime import datetime
from jose import JWTError, jwt
import qrcode
import base64
from io import BytesIO
from src.auth.schemas import PlanCurrentCompanyUser
from src.common.dependencies import get_current_company_user, get_plan_user
from src.constants import CompanyPlanEnum, UserType,ApplicationUserRoleEnum
from fastapi import Depends, HTTPException, status,Request
from passlib.context import CryptContext
import bcrypt as _bcrypt

#global schema 

from src.schemas.application_user import CurrentApplicationUser
from src.schemas.compnay_user import CurrentCompanyUser


def generate_password(length=8):
    # Define the possible characters for the password
    characters = string.ascii_letters + string.digits + string.punctuation
    # Randomly choose characters and form the password
    password = ''.join(random.choice(characters) for _ in range(length))
    return password


SECRET_KEY = "thrinath@123"  
ALGORITHM = "HS256"


def create_jwt_access_token(data: dict, expires_delta: timedelta = None,ACCESS_TOKEN_EXPIRE_MINUTES = 200):
    to_encode = data.copy()
    expire = datetime.now(timezone.utc) + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def encrypt_reset_payload(payload: dict) -> str:
    token  = create_jwt_access_token(data=payload)
    return token

def decrypt_reset_token(token: str) -> dict:
    try:
        data = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        # Extract user details
        print(data)
        return data
    
    except JWTError:
        print(JWTError)
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials....",
            headers={"WWW-Authenticate": "Bearer"},
        )


#user_add_delete_update_access_check ----> old name
def add_delete_update_company_user_access_check(currentCompanyUser:CurrentCompanyUser,action):

    if currentCompanyUser.role.lower() != "admin" or currentCompanyUser.department.lower() != "it":
        return False
    else:
        return True
    
def add_delete_update_application_user_access_check(currentApplicationUser:CurrentApplicationUser,action):
    print(currentApplicationUser)
    print(currentApplicationUser.role.lower(),ApplicationUserRoleEnum.ADMIN.value,currentApplicationUser.user_type,UserType.APPLICATION.value)
    
    if currentApplicationUser.role.lower() == ApplicationUserRoleEnum.ADMIN.value and currentApplicationUser.user_type == UserType.APPLICATION.value:
        return True
    else:
        return False

def generate_qr_code_image(data: str) -> str:
    # Create QR code from the otpauth_url
    qr = qrcode.make(data)
    # Save to file if path provided
    
    buf = BytesIO()
    qr.save(buf, format='PNG')
    img_base64 = base64.b64encode(buf.getvalue()).decode("utf-8")
    return img_base64

def _to_bytes(password: str) -> bytes:
    # bcrypt 4.x+ raises if password > 72 bytes; truncate first.
    return password.encode("utf-8")[:72]

class _BcryptContext:
    def hash(self, password: str) -> str:
        return _bcrypt.hashpw(_to_bytes(password), _bcrypt.gensalt()).decode("utf-8")

    def verify(self, password: str, hashed: str) -> bool:
        hashed_bytes = hashed.encode("utf-8") if isinstance(hashed, str) else hashed
        return _bcrypt.checkpw(_to_bytes(password), hashed_bytes)

pwd_context = _BcryptContext()

def require_minimum_plan(min_plan: List[CompanyPlanEnum]):
    plan_order = [CompanyPlanEnum.BASIC, CompanyPlanEnum.EXPERIENCED, CompanyPlanEnum.PROFICIENT]

    def checker(user: CurrentCompanyUser = Depends(get_current_company_user)):
        if user.plan not in plan_order:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Access denied. Requires plan in: {[plan.value for plan in plan_order]}"
            )
        return user
    return checker
