from typing import Optional, Tuple
from sqlalchemy.orm import Session
from app.models.user import User
from app.repositories.user import user_repository
from app.schemas.user import UserCreate
from app.schemas.token import Token
from app.core import security
from app.core.exceptions import BadRequestException, UnauthorizedException
from jose import jwt, JWTError

class AuthService:
    """Business logic layer for handling authentication and token lifecycle."""

    def register_user(self, db: Session, user_in: UserCreate) -> User:
        """Register a new customer account after validation."""
        # 1. Pastikan email belum terdaftar
        existing_user = user_repository.get_by_email(db, user_in.email)
        if existing_user:
            raise BadRequestException("This email address is already registered.")

        # 2. Hash password dan simpan model
        new_user = User(
            email=user_in.email.lower(),
            hashed_password=security.get_password_hash(user_in.password),
            full_name=user_in.full_name,
            is_active=True,
            is_superuser=False
        )
        return user_repository.create(db, obj_in=new_user)

    def authenticate_user(self, db: Session, email: str, password: str) -> User:
        """Authenticate user credentials and return User model if valid."""
        user = user_repository.get_by_email(db, email)
        if not user or not user.is_active:
            raise UnauthorizedException("Incorrect email or password.")
            
        if not security.verify_password(password, user.hashed_password):
            raise UnauthorizedException("Incorrect email or password.")
            
        return user

    def generate_tokens(self, user: User) -> Token:
        """Generate Access and Refresh tokens for a successfully validated User."""
        access_token = security.create_access_token(subject=user.id)
        refresh_token = security.create_refresh_token(subject=user.id)
        return Token(
            access_token=access_token,
            refresh_token=refresh_token,
            token_type="bearer"
        )

    def refresh_access_token(self, db: Session, refresh_token: str) -> Token:
        """Validate a refresh token and return a new access & refresh token pair."""
        try:
            payload = jwt.decode(
                refresh_token, 
                security.settings.SECRET_KEY, 
                algorithms=[security.ALGORITHM]
            )
            user_id: str = payload.get("sub")
            token_type: str = payload.get("type")
            
            if user_id is None or token_type != "refresh":
                raise UnauthorizedException("Invalid refresh token payload.")
        except JWTError:
            raise UnauthorizedException("Invalid or expired refresh token.")

        user = user_repository.get(db, id=user_id)
        if not user or not user.is_active:
            raise UnauthorizedException("User account is inactive or not found.")

        # Hasilkan token baru
        return self.generate_tokens(user)

auth_service = AuthService()
