from pydantic import BaseModel
from datetime import datetime, timedelta
from jose import JWTError, jwt
from typing import Annotated
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm import Session

from db.schemas.Schemas import Usuario as ModelUsuario
from db.crud.Usuario import Usuario
from db import database

SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256"

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


def get_db():
    session = database.SessionLocal()
    try:
        yield session
    except:
        session.close()


class Token(BaseModel):
    access_token: str
    token_type: str


class TokenData(BaseModel):
    id: int | None = None
    nome: str | None = None
    login: str | None = None


def create_access_token(data: dict, expires_delta: timedelta | None = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(days=1)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def get_current_user(token: Annotated[str, Depends(oauth2_scheme)], session: Session = Depends(get_db)) -> ModelUsuario:
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Não autorizado.",
        headers={
            "WWW_Authenticate": "Bearer"
        }
    )

    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        if payload is None:
            raise credentials_exception
        token_data = TokenData(id=payload.get("id"), nome=payload.get("nome"), login=payload.get("login"))
    except JWTError:
        raise credentials_exception

    user = Usuario().get_usuario_por_id(token_data.id, session)

    if user is None:
        raise credentials_exception

    return user

def is_autenticado(token: Annotated[str, Depends(oauth2_scheme)], session: Session = Depends(get_db)) -> bool:
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        if payload is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Usuário não autenticado."
            )
        token_data = TokenData(id=payload.get("id"), nome=payload.get("nome"), login=payload.get("login"))
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Usuário não autenticado."
        )

    user = Usuario().get_usuario_por_id(token_data.id, session)

    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Usuário não autenticado."
        )

    return True