"""
Authentication helper for the Scheduler service.

Supports two auth strategies (checked in order):
1. JWT Bearer token — validated with the same HS256 secret as Laravel.
2. X-Token header  — looked up in the MYL_MASTER.users table (mirrors
   PHP AuthHelper::verifyAuth).

If neither header is present, the request is rejected with 401.
"""

import os
import logging

import jwt  # PyJWT
from dotenv import load_dotenv
from fastapi import Request, HTTPException

from db import get_master_connection

logger = logging.getLogger(__name__)

_ENV_PATH = os.path.join(os.path.dirname(__file__), "..", ".env")
load_dotenv(_ENV_PATH)


def _get_jwt_secret() -> str:
    """
    Resolve the JWT secret following a secure multi-tiered approach:
    environment variable -> .env file value (already loaded).
    """
    secret = os.getenv("JWT_SECRET")
    if not secret:
        raise RuntimeError(
            "JWT_SECRET is not configured. "
            "Set it in the .env file or as an environment variable."
        )
    return secret


JWT_ALGORITHM = "HS256"


def _verify_jwt(token: str) -> dict:
    """Decode and verify a JWT token.  Returns the payload dict."""
    secret = _get_jwt_secret()
    try:
        payload = jwt.decode(
            token,
            secret,
            algorithms=[JWT_ALGORITHM],
            options={
                "require": ["exp", "iat", "sub"],
            },
        )
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token has expired.")
    except jwt.InvalidTokenError as exc:
        raise HTTPException(
            status_code=401, detail=f"Invalid token: {exc}"
        )


def _verify_x_token(token: str) -> dict:
    """Look up the token in MYL_MASTER.users (mirrors PHP AuthHelper)."""
    with get_master_connection() as conn:
        with conn.cursor() as cur:
            cur.execute(
                "SELECT * FROM users WHERE token = %s LIMIT 1",
                (token,),
            )
            user = cur.fetchone()

    if not user:
        raise HTTPException(
            status_code=401, detail="Invalid token. Authentication failed."
        )
    return user


def authenticate(request: Request) -> dict:
    """
    Authenticate the incoming request.

    Returns a dict representing the authenticated user/payload.
    Raises HTTPException(401) on failure.
    """
    # Strategy 1: Authorization Bearer header (JWT)
    auth_header = request.headers.get("Authorization", "")
    if auth_header.startswith("Bearer "):
        jwt_token = auth_header[7:]
        return _verify_jwt(jwt_token)

    # Strategy 2: X-Token header (DB lookup)
    x_token = request.headers.get("X-Token", "")
    if x_token:
        return _verify_x_token(x_token)

    raise HTTPException(
        status_code=401,
        detail="Authentication required. Provide Authorization Bearer or X-Token header.",
    )
