# app/services/auth_service.py
"""
Authentication service for user login and vendor access control.

This module provides:
- User authentication and JWT token generation
- Vendor access verification
- Password hashing utilities

Note: Customer registration is handled by CustomerService.
      User (admin/vendor team) creation is handled by their respective services.
"""

import logging
from typing import Any

from sqlalchemy.orm import Session

from app.exceptions import (
    InvalidCredentialsException,
    UserNotActiveException,
)
from middleware.auth import AuthManager
from models.database.user import User
from models.database.vendor import Vendor, VendorUser
from models.schema.auth import UserLogin

logger = logging.getLogger(__name__)


class AuthService:
    """Service class for authentication operations."""

    def __init__(self):
        """Initialize with AuthManager instance."""
        self.auth_manager = AuthManager()

    def login_user(self, db: Session, user_credentials: UserLogin) -> dict[str, Any]:
        """
        Login user and return JWT token with user data.

        Args:
            db: Database session
            user_credentials: User login credentials

        Returns:
            Dictionary containing access token data and user object

        Raises:
            InvalidCredentialsException: If authentication fails
            UserNotActiveException: If user account is not active
        """
        user = self.auth_manager.authenticate_user(
            db, user_credentials.email_or_username, user_credentials.password
        )
        if not user:
            raise InvalidCredentialsException("Incorrect username or password")

        if not user.is_active:
            raise UserNotActiveException("User account is not active")

        token_data = self.auth_manager.create_access_token(user)

        logger.info(f"User logged in: {user.username}")
        return {"token_data": token_data, "user": user}

    def hash_password(self, password: str) -> str:
        """
        Hash a password.

        Args:
            password: Plain text password

        Returns:
            Hashed password string
        """
        return self.auth_manager.hash_password(password)

    def get_vendor_by_code(self, db: Session, vendor_code: str) -> Vendor | None:
        """
        Get active vendor by vendor code.

        Args:
            db: Database session
            vendor_code: Vendor code to look up

        Returns:
            Vendor if found and active, None otherwise
        """
        return (
            db.query(Vendor)
            .filter(Vendor.vendor_code == vendor_code.upper(), Vendor.is_active == True)
            .first()
        )

    def get_user_vendor_role(
        self, db: Session, user: User, vendor: Vendor
    ) -> tuple[bool, str | None]:
        """
        Check if user has access to vendor and return their role.

        Args:
            db: Database session
            user: User to check
            vendor: Vendor to check access for

        Returns:
            Tuple of (has_access: bool, role_name: str | None)
        """
        # Check if user is vendor owner (via company ownership)
        if vendor.company and vendor.company.owner_user_id == user.id:
            return True, "Owner"

        # Check if user is team member
        vendor_user = (
            db.query(VendorUser)
            .filter(
                VendorUser.user_id == user.id,
                VendorUser.vendor_id == vendor.id,
                VendorUser.is_active == True,
            )
            .first()
        )

        if vendor_user:
            return True, vendor_user.role.name

        return False, None

    def find_user_vendor(self, user: User) -> tuple[Vendor | None, str | None]:
        """
        Find which vendor a user belongs to when no vendor context is provided.

        Checks owned companies first, then vendor memberships.

        Args:
            user: User to find vendor for

        Returns:
            Tuple of (vendor: Vendor | None, role: str | None)
        """
        # Check owned vendors first (via company ownership)
        for company in user.owned_companies:
            if company.vendors:
                return company.vendors[0], "Owner"

        # Check vendor memberships
        if user.vendor_memberships:
            active_membership = next(
                (vm for vm in user.vendor_memberships if vm.is_active), None
            )
            if active_membership:
                return active_membership.vendor, active_membership.role.name

        return None, None


# Create service instance
auth_service = AuthService()
