from datetime import datetime, timedelta
from typing import Optional, Dict, Any

from fastapi import Depends, HTTPException
from pydantic import EmailStr
from starlette import status

from app.config import settings
from passlib.context import CryptContext
from jose import JWTError, jwt
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from app.schemas.base_response import BaseResponse
from fastapi.responses import JSONResponse

from app.models.user import User
from app.schemas.user import UserResponse

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password):
    return pwd_context.hash(password)


def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
    return encoded_jwt


async def authenticate_user(email: EmailStr, password: str, user_service) -> Optional[User]:
    user = await user_service.get_user_by_email_db(email)
    if not user:
        return None
    if not verify_password(password, user["password"]):
        return None
    return user


async def get_token_data(token: str = Depends(oauth2_scheme)) -> Dict[str, Any]:
    """Validate and decode token"""
    credentials_exception = JSONResponse(
        status_code=status.HTTP_401_UNAUTHORIZED,
        content=BaseResponse(success=False, message="Could not validate credentials").dict(),
        headers={"WWW-Authenticate": "Bearer"},
    )

    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])

        # Check token type
        token_type = payload.get("type")
        if token_type != "bearer":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail=BaseResponse(success=False, message="Invalid token type").dict()
            )

        email: str = payload.get("sub")
        if email is None:
            return credentials_exception

        return {"email": email}
    except JWTError:
        return credentials_exception