from fastapi import HTTPException, status
from sqlmodel import Session

from app.models.user import User, Role
from app.schemas.user import UserCreate
from app.utils.tokens import create_access_token, create_refresh_token, decode_token
from app.core.security import hash_password, verify_password
from app.repositories.user_repo import UserRepository
from app.core.constants import (
    ERR_EMAIL_REGISTERED,
    ERR_INVALID_CREDENTIALS,
    ERR_INVALID_TOKEN,
    ERR_REFRESH_TOKEN,
    ERR_ONLY_SUPERADMIN_CAN_CREATE_ADMINS
)

class AuthService:
    """Service exposing auth-related business operations."""

    @staticmethod
    def signup(data: UserCreate, session: Session):
        """Create a new standard user and return tokens."""
        existing = UserRepository.get_by_email(session, data.email)
        if existing:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERR_EMAIL_REGISTERED)

        user = User(
            email=data.email,
            first_name=data.first_name,
            last_name=data.last_name,
            hashed_password=hash_password(data.password),
            phone=data.phone,
            role=Role.USERS,
        )

        user = UserRepository.create(session, user)
        access = create_access_token(sub=user.email)
        refresh = create_refresh_token(sub=user.email)

        user.refresh_token = refresh
        session.commit()

        return {"access_token": access, "refresh_token": refresh, "token_type": "bearer"}

    @staticmethod
    def login(email: str, password: str, session: Session):
        """Authenticate and return tokens."""
        user = UserRepository.get_by_email(session, email)
        if not user or not verify_password(password, user.hashed_password):
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERR_INVALID_CREDENTIALS)

        access = create_access_token(sub=user.email)
        refresh = create_refresh_token(sub=user.email)

        user.refresh_token = refresh
        session.commit()

        return {"access_token": access, "refresh_token": refresh, "token_type": "bearer"}

    @staticmethod
    def refresh_token(refresh_token: str, session: Session):
        """Exchange a valid refresh token for a new token pair."""
        payload = decode_token(refresh_token)
        if payload.get("type") != "refresh":
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERR_INVALID_TOKEN)

        email = payload.get("sub")
        user = UserRepository.get_by_email(session, email)

        if not user or user.refresh_token != refresh_token:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERR_REFRESH_TOKEN)

        new_access = create_access_token(sub=user.email)
        new_refresh = create_refresh_token(sub=user.email)

        user.refresh_token = new_refresh
        session.commit()

        return {"access_token": new_access, "refresh_token": new_refresh, "token_type": "bearer"}

    @staticmethod
    def logout(user: User, session: Session):
        """Revoke refresh token -> user logged out on all devices."""
        user.refresh_token = None
        session.commit()
        return {"message": "Successfully logged out."}

    @staticmethod
    def register_admin(data: UserCreate, session: Session, current_super: User):
        """
        SUPERADMIN-only: create an ADMIN user.
        'current_super' param is passed from dependency checks in routes.
        """
        if current_super.role != Role.SUPERADMIN:
            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERR_ONLY_SUPERADMIN_CAN_CREATE_ADMINS)

        existing = UserRepository.get_by_email(session, data.email)
        if existing:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERR_EMAIL_REGISTERED)

        admin = User(
            email=data.email,
            first_name=data.first_name,
            last_name=data.last_name,
            hashed_password=hash_password(data.password),
            phone=data.phone,
            role=Role.ADMIN,
            is_active=True,
        )
        admin = UserRepository.create(session, admin)
        return admin