from __future__ import annotations

from datetime import datetime, timedelta, timezone
from typing import Any, Dict

import bcrypt
import jwt
from passlib.context import CryptContext


if not hasattr(bcrypt, "__about__"):
    class _BcryptAbout:
        __version__ = getattr(bcrypt, "__version__", "")

    bcrypt.__about__ = _BcryptAbout()  # type: ignore[attr-defined]


pwd_context = CryptContext(
    schemes=["bcrypt_sha256", "bcrypt"],
    default="bcrypt_sha256",
    deprecated="auto",
)


def get_password_hash(plain_password: str) -> str:
    # Passlib faz o pré-hash com SHA-256 no bcrypt_sha256,
    # eliminando o limite prático de 72 bytes do bcrypt tradicional.
    # Garante também que plain_password é str.
    if plain_password is None:
        raise ValueError("plain_password is None")
    return pwd_context.hash(plain_password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    if not hashed_password:
        return False
    return pwd_context.verify(plain_password, hashed_password)


def create_access_token(
    sub: str, expires_seconds: int, secret: str, algorithm: str
) -> str:
    now = datetime.now(tz=timezone.utc)
    expire = now + timedelta(seconds=expires_seconds)
    payload: Dict[str, Any] = {"sub": sub, "exp": expire}
    token = jwt.encode(payload, secret, algorithm=algorithm)
    return token


def parse_token(token: str, secret: str, algorithm: str) -> Dict[str, Any]:
    return jwt.decode(token, secret, algorithms=[algorithm])
