# app/exceptions/team.py
"""
Team management specific exceptions.
"""

from typing import Any

from .base import (
    AuthorizationException,
    BusinessLogicException,
    ConflictException,
    ResourceNotFoundException,
    ValidationException,
)


class TeamMemberNotFoundException(ResourceNotFoundException):
    """Raised when a team member is not found."""

    def __init__(self, user_id: int, vendor_id: int | None = None):
        details = {"user_id": user_id}
        if vendor_id:
            details["vendor_id"] = vendor_id
            message = (
                f"Team member with user ID '{user_id}' not found in vendor {vendor_id}"
            )
        else:
            message = f"Team member with user ID '{user_id}' not found"

        super().__init__(
            resource_type="TeamMember",
            identifier=str(user_id),
            message=message,
            error_code="TEAM_MEMBER_NOT_FOUND",
            details=details,
        )


class TeamMemberAlreadyExistsException(ConflictException):
    """Raised when trying to add a user who is already a team member."""

    def __init__(self, user_id: int, vendor_id: int):
        super().__init__(
            message=f"User {user_id} is already a team member of vendor {vendor_id}",
            error_code="TEAM_MEMBER_ALREADY_EXISTS",
            details={
                "user_id": user_id,
                "vendor_id": vendor_id,
            },
        )


class TeamInvitationNotFoundException(ResourceNotFoundException):
    """Raised when a team invitation is not found."""

    def __init__(self, invitation_token: str):
        super().__init__(
            resource_type="TeamInvitation",
            identifier=invitation_token,
            message=f"Team invitation with token '{invitation_token}' not found or expired",
            error_code="TEAM_INVITATION_NOT_FOUND",
        )


class TeamInvitationExpiredException(BusinessLogicException):
    """Raised when trying to accept an expired invitation."""

    def __init__(self, invitation_token: str):
        super().__init__(
            message="Team invitation has expired",
            error_code="TEAM_INVITATION_EXPIRED",
            details={"invitation_token": invitation_token},
        )


class TeamInvitationAlreadyAcceptedException(ConflictException):
    """Raised when trying to accept an already accepted invitation."""

    def __init__(self, invitation_token: str):
        super().__init__(
            message="Team invitation has already been accepted",
            error_code="TEAM_INVITATION_ALREADY_ACCEPTED",
            details={"invitation_token": invitation_token},
        )


class UnauthorizedTeamActionException(AuthorizationException):
    """Raised when user tries to perform team action without permission."""

    def __init__(
        self,
        action: str,
        user_id: int | None = None,
        required_permission: str | None = None,
    ):
        details = {"action": action}
        if user_id:
            details["user_id"] = user_id
        if required_permission:
            details["required_permission"] = required_permission

        super().__init__(
            message=f"Unauthorized to perform action: {action}",
            error_code="UNAUTHORIZED_TEAM_ACTION",
            details=details,
        )


class CannotRemoveOwnerException(BusinessLogicException):
    """Raised when trying to remove the vendor owner from team."""

    def __init__(self, user_id: int, vendor_id: int):
        super().__init__(
            message="Cannot remove vendor owner from team",
            error_code="CANNOT_REMOVE_OWNER",
            details={
                "user_id": user_id,
                "vendor_id": vendor_id,
            },
        )


class CannotModifyOwnRoleException(BusinessLogicException):
    """Raised when user tries to modify their own role."""

    def __init__(self, user_id: int):
        super().__init__(
            message="Cannot modify your own role",
            error_code="CANNOT_MODIFY_OWN_ROLE",
            details={"user_id": user_id},
        )


class RoleNotFoundException(ResourceNotFoundException):
    """Raised when a role is not found."""

    def __init__(self, role_id: int, vendor_id: int | None = None):
        details = {"role_id": role_id}
        if vendor_id:
            details["vendor_id"] = vendor_id
            message = f"Role with ID '{role_id}' not found in vendor {vendor_id}"
        else:
            message = f"Role with ID '{role_id}' not found"

        super().__init__(
            resource_type="Role",
            identifier=str(role_id),
            message=message,
            error_code="ROLE_NOT_FOUND",
            details=details,
        )


class InvalidRoleException(ValidationException):
    """Raised when role data is invalid."""

    def __init__(
        self,
        message: str = "Invalid role data",
        field: str | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(
            message=message,
            field=field,
            details=details,
        )
        self.error_code = "INVALID_ROLE_DATA"


class InsufficientTeamPermissionsException(AuthorizationException):
    """Raised when user lacks required team permissions for an action."""

    def __init__(
        self,
        required_permission: str,
        user_id: int | None = None,
        action: str | None = None,
    ):
        details = {"required_permission": required_permission}
        if user_id:
            details["user_id"] = user_id
        if action:
            details["action"] = action

        message = f"Insufficient team permissions. Required: {required_permission}"

        super().__init__(
            message=message,
            error_code="INSUFFICIENT_TEAM_PERMISSIONS",
            details=details,
        )


class MaxTeamMembersReachedException(BusinessLogicException):
    """Raised when vendor has reached maximum team members limit."""

    def __init__(self, max_members: int, vendor_id: int):
        super().__init__(
            message=f"Maximum number of team members reached ({max_members})",
            error_code="MAX_TEAM_MEMBERS_REACHED",
            details={
                "max_members": max_members,
                "vendor_id": vendor_id,
            },
        )


class TeamValidationException(ValidationException):
    """Raised when team operation validation fails."""

    def __init__(
        self,
        message: str = "Team operation validation failed",
        field: str | None = None,
        validation_errors: dict[str, str] | None = None,
    ):
        details = {}
        if validation_errors:
            details["validation_errors"] = validation_errors

        super().__init__(
            message=message,
            field=field,
            details=details,
        )
        self.error_code = "TEAM_VALIDATION_FAILED"


class InvalidInvitationDataException(ValidationException):
    """Raised when team invitation data is invalid."""

    def __init__(
        self,
        message: str = "Invalid invitation data",
        field: str | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(
            message=message,
            field=field,
            details=details,
        )
        self.error_code = "INVALID_INVITATION_DATA"


# ============================================================================
# NEW: Add InvalidInvitationTokenException
# ============================================================================


class InvalidInvitationTokenException(ValidationException):
    """Raised when invitation token is invalid, expired, or already used.

    This is a general exception for any invitation token validation failure.
    Use this when checking invitation tokens during the acceptance flow.
    """

    def __init__(
        self,
        message: str = "Invalid or expired invitation token",
        invitation_token: str | None = None,
    ):
        details = {}
        if invitation_token:
            details["invitation_token"] = invitation_token

        super().__init__(
            message=message,
            field="invitation_token",
            details=details,
        )
        self.error_code = "INVALID_INVITATION_TOKEN"
