"""
[C-01] JWT Authentication Module
Implement Bearer token authentication for API endpoints.
"""
import os
from datetime import datetime, timedelta, timezone
from typing import Optional
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer
from jose import JWTError, jwt
from pydantic import BaseModel

# Configuration
SECRET_KEY = os.environ.get("JWT_SECRET_KEY")
if not SECRET_KEY:
    # Generate fallback key for dev (NOT FOR PRODUCTION)
    import secrets
    SECRET_KEY = secrets.token_urlsafe(32)
    import sys
    print(f"[WARNING] JWT_SECRET_KEY not set. Generated ephemeral key: {SECRET_KEY[:20]}...", file=sys.stderr)

ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 480  # 8 hours

security = HTTPBearer()


class TokenData(BaseModel):
    sub: int  # user_id
    username: str
    role: str
    exp: datetime


class TokenResponse(BaseModel):
    access_token: str
    token_type: str
    user_id: int
    username: str
    role: str


def create_access_token(user_id: int, username: str, role: str, expires_delta: Optional[timedelta] = None):
    """Create JWT token with expiration."""
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)

    to_encode = {
        "sub": str(user_id),  # JWT spec requires sub to be a string
        "username": username,
        "role": role,
        "exp": expire,
        "iat": datetime.now(timezone.utc)
    }
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


async def get_current_user(credentials = Depends(security)):
    """
    Dependency that validates JWT token from Authorization header.
    Returns TokenData with user_id, username, role.
    """
    token = credentials.credentials
    import logging
    log = logging.getLogger("ainventory")
    log.debug(f"[AUTH] Validating token (first 10 chars): {token[:10] if token else 'None'}")
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: int = int(payload.get("sub"))  # sub is stored as string, convert back to int
        username: str = payload.get("username")
        role: str = payload.get("role")
        log.debug(f"[AUTH] Token valid — user_id={user_id}, username={username}, role={role}")

        if user_id is None or username is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid token claims"
            )
        token_data = TokenData(
            sub=user_id,
            username=username,
            role=role,
            exp=datetime.fromtimestamp(payload.get("exp"), tz=timezone.utc)
        )
    except JWTError as e:
        log.error(f"[AUTH] JWTError: {type(e).__name__}: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return token_data


async def get_current_admin(current_user: TokenData = Depends(get_current_user)):
    """Dependency that checks if user has 'admin' role."""
    if current_user.role != "admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin role required"
        )
    return current_user
