# generated by fastapi-codegen:
#   filename:  connector
#   timestamp: 2025-09-03T15:14:14+00:00

from abc import ABC, abstractmethod
from datetime import datetime, timedelta

import jwt
from fastapi import HTTPException


class UserDataHandler(ABC):

    @abstractmethod
    def validate_credentials(self, username: str, password: str) -> bool:
        """Validate username and password against the user database."""
        raise NotImplementedError

    @abstractmethod
    def valid_user(self, username):
        """Validate username"""
        raise NotImplementedError


class BearerTokenHandler:

    def __init__(
        self, token_expiration_hours, token_secret, user_handler: UserDataHandler
    ):
        self.token_expiration_hours = token_expiration_hours
        self.token_secret = token_secret
        self.user_handler = user_handler

    def generate_token(self, username: str, password: str) -> str:
        """Generate a JWT token using PyJWT library."""
        # Validate that user exists before generating token
        if not self.user_handler.validate_credentials(username, password):
            raise HTTPException(status_code=401, detail="Invalid username or password")

        # Create token payload
        payload = {
            "sub": username,  # Subject (user identifier)
            "iat": datetime.utcnow(),  # Issued at
            "exp": datetime.utcnow()
            + timedelta(hours=self.token_expiration_hours),  # Expiration
            "type": "access_token",
        }

        # Generate JWT token using PyJWT
        return jwt.encode(payload, self.token_secret, algorithm="HS256")

    def validate_token(self, token: str) -> dict:
        """Validate and decode a JWT token using PyJWT library."""
        try:
            # Remove 'Bearer ' prefix if present
            if token.startswith('Bearer '):
                token = token[7:]

            # Decode and validate token using PyJWT
            payload = jwt.decode(
                token,
                self.token_secret,
                algorithms=["HS256"],
                options={
                    "verify_exp": True,
                    "verify_iat": True,
                    "verify_signature": True,
                },
            )

            # Verify token type
            if payload.get('type') != 'access_token':
                raise jwt.InvalidTokenError("Invalid token type")

            # Verify that the user still exists
            username = payload.get('sub')
            if username and not self.user_handler.valid_user(username):
                raise jwt.InvalidTokenError("User no longer exists")

            return payload

        except jwt.ExpiredSignatureError:
            raise HTTPException(status_code=401, detail="Token has expired")
        except jwt.InvalidTokenError as e:
            raise HTTPException(status_code=401, detail=f"Invalid token: {str(e)}")
        except Exception as e:
            raise HTTPException(
                status_code=500, detail=f"Token validation error: {str(e)}"
            )

    def get_current_user(self, token: str) -> str:
        """Extract and return the current user from a valid token."""
        payload = self.validate_token(token)
        return payload.get('sub')

    def is_token_valid(self, token: str) -> bool:
        """Check if a token is valid without raising exceptions."""
        try:
            self.validate_token(token)
            return True
        except HTTPException:
            return False
