"""
FastAPI Users configuration for JWT-based authentication.
Provides user manager, JWT strategy, and authentication backend.
"""
import logging
import os
from typing import Optional

logger = logging.getLogger(__name__)
from fastapi import Depends
from fastapi_users import FastAPIUsers, BaseUserManager
from fastapi_users.authentication import (
    AuthenticationBackend,
    BearerTransport,
    JWTStrategy,
)
from fastapi_users_db_sqlalchemy import SQLAlchemyUserDatabase
from app.models import User
from app.database import get_async_session
from sqlalchemy.ext.asyncio import AsyncSession

# JWT Configuration - SECURITY: JWT_SECRET is required for production
JWT_SECRET = os.getenv("JWT_SECRET")
if not JWT_SECRET:
    if os.getenv("ENVIRONMENT") == "production":
        raise ValueError(
            "JWT_SECRET environment variable is required in production. "
            "Generate one with: openssl rand -hex 32"
        )
    else:
        JWT_SECRET = "dev-only-insecure-secret-CHANGE-IN-PRODUCTION"
        logger.warning(
            "JWT_SECRET not set — using insecure dev secret. "
            "Generate one with: openssl rand -hex 32"
        )

JWT_LIFETIME_SECONDS = int(os.getenv("JWT_LIFETIME_SECONDS", 3600))  # 1 hour default


class UserManager(BaseUserManager[User, str]):
    """User manager for handling user operations"""
    reset_password_token_secret = JWT_SECRET
    verification_token_secret = JWT_SECRET

    # Our User.id is a string UUID; return it unchanged from tokens
    def parse_id(self, user_id: str) -> str:
        return user_id

    async def generate_token(self, data: dict) -> str:
        """Generate a JWT token for password reset"""
        from jose import jwt
        from datetime import datetime, timedelta

        # Token expires in 1 hour
        expires_delta = timedelta(hours=1)
        expire = datetime.utcnow() + expires_delta

        to_encode = data.copy()
        to_encode.update({"exp": expire})

        encoded_jwt = jwt.encode(
            to_encode,
            self.reset_password_token_secret,
            algorithm="HS256"
        )
        return encoded_jwt

    async def verify_token(self, token: str) -> dict | None:
        """Verify and decode a JWT token"""
        from jose import jwt, JWTError

        try:
            payload = jwt.decode(
                token,
                self.reset_password_token_secret,
                algorithms=["HS256"]
            )
            return payload
        except JWTError:
            return None


async def get_user_db(
    session: AsyncSession = Depends(get_async_session),
):
    """Get user database adapter backed by AsyncSession"""
    yield SQLAlchemyUserDatabase(session, User)


async def get_user_manager(
    user_db: SQLAlchemyUserDatabase = Depends(get_user_db),
):
    """Get user manager"""
    yield UserManager(user_db)


# Bearer transport for JWT in Authorization header
bearer_transport = BearerTransport(tokenUrl="/api/auth/jwt/login")

# JWT strategy
def get_jwt_strategy() -> JWTStrategy:
    return JWTStrategy(secret=JWT_SECRET, lifetime_seconds=JWT_LIFETIME_SECONDS)


# Authentication backend
auth_backend = AuthenticationBackend(
    name="jwt",
    transport=bearer_transport,
    get_strategy=get_jwt_strategy,
)

# FastAPI Users instance
fastapi_users = FastAPIUsers[User, str](
    get_user_manager,
    [auth_backend],
)

# Dependency for current active user
current_active_user = fastapi_users.current_user(active=True)
