# -*- coding: utf-8 -*-
"""Location: ./mcpgateway/services/personal_team_service.py
Copyright 2026
SPDX-License-Identifier: Apache-2.0
Authors: Mihai Criveti

Personal Team Service.
This module provides automatic personal team creation and management
for email-based user authentication system.

Examples:
    >>> from unittest.mock import Mock
    >>> service = PersonalTeamService(Mock())
    >>> isinstance(service, PersonalTeamService)
    True
    >>> hasattr(service, 'db')
    True
"""

# Standard
from typing import Optional

# Third-Party
from sqlalchemy.orm import Session

# First-Party
from mcpgateway.config import settings
from mcpgateway.db import EmailTeam, EmailTeamMember, EmailTeamMemberHistory, EmailUser, utc_now
from mcpgateway.services.logging_service import LoggingService
from mcpgateway.utils.create_slug import slugify

# Initialize logging
logging_service = LoggingService()
logger = logging_service.get_logger(__name__)


class PersonalTeamService:
    """Service for managing personal teams.

    This service handles automatic creation of personal teams for users
    and manages team membership for personal workspaces.

    Attributes:
        db (Session): SQLAlchemy database session

    Examples:
        >>> from unittest.mock import Mock
        >>> service = PersonalTeamService(Mock())
        >>> service.__class__.__name__
        'PersonalTeamService'
        >>> hasattr(service, 'db')
        True
    """

    def __init__(self, db: Session):
        """Initialize the personal team service.

        Args:
            db: SQLAlchemy database session

        Examples:
            >>> from unittest.mock import Mock
            >>> service = PersonalTeamService(Mock())
            >>> hasattr(service, 'db') and service.db is not None or service.db is None
            True
        """
        self.db = db

    async def create_personal_team(self, user: EmailUser) -> EmailTeam:
        """Create a personal team for a user.

        Args:
            user: EmailUser instance for whom to create personal team

        Returns:
            EmailTeam: The created personal team

        Raises:
            ValueError: If user already has a personal team
            Exception: If team creation fails

        Examples:
            Personal team creation is handled automatically during user registration.
            The team name is derived from the user's full name or email.

            After creation, a record is inserted into EmailTeamMemberHistory to track the membership event.

            Note:
                This method is async and cannot be directly called with 'await' in doctest. To test async methods, use an event loop in real tests.

            # Example (not executable in doctest):
            # import asyncio
            # team = asyncio.run(service.create_personal_team(user))
        """
        try:
            # Check if user already has a personal team
            existing_team = self.db.query(EmailTeam).filter(EmailTeam.created_by == user.email, EmailTeam.is_personal.is_(True), EmailTeam.is_active.is_(True)).first()

            if existing_team:
                logger.warning(f"User {user.email} already has a personal team: {existing_team.id}")
                raise ValueError(f"User {user.email} already has a personal team")

            # Generate team name from user's display name
            display_name = user.get_display_name()
            team_name = f"{display_name}'s Team"

            # Create team slug — use prefix from config if set, otherwise derive from display name
            prefix = slugify(settings.personal_team_prefix.strip()) if settings.personal_team_prefix.strip() else ""
            if prefix:
                email_slug = user.email.replace("@", "-").replace(".", "-").lower()
                team_slug = f"{prefix}-{email_slug}"
            else:
                team_slug = slugify(team_name)

            # Create the personal team
            team = EmailTeam(
                name=team_name,
                slug=team_slug,  # Will be auto-generated by event listener if not set
                description=f"Personal workspace for {user.email}",
                created_by=user.email,
                is_personal=True,
                visibility="private",
                is_active=True,
            )

            self.db.add(team)
            self.db.flush()  # Get the team ID

            # Add the user as the owner of their personal team
            membership = EmailTeamMember(team_id=team.id, user_email=user.email, role="owner", joined_at=utc_now(), is_active=True)

            self.db.add(membership)
            self.db.flush()  # Get the membership ID
            # Insert history record
            history = EmailTeamMemberHistory(team_member_id=membership.id, team_id=team.id, user_email=user.email, role="owner", action="added", action_by=user.email, action_timestamp=utc_now())
            self.db.add(history)
            self.db.commit()

            logger.info(f"Created personal team '{team.name}' for user {user.email}")
            return team

        except Exception as e:
            self.db.rollback()
            logger.error(f"Failed to create personal team for {user.email}: {e}")
            raise

    async def get_personal_team(self, user_email: str) -> Optional[EmailTeam]:
        """Get the personal team for a user.

        Args:
            user_email: Email address of the user

        Returns:
            EmailTeam: The user's personal team or None if not found

        Examples:
            >>> import asyncio
            >>> from unittest.mock import Mock
            >>> service = PersonalTeamService(Mock())
            >>> asyncio.iscoroutinefunction(service.get_personal_team)
            True
        """
        try:
            team = self.db.query(EmailTeam).filter(EmailTeam.created_by == user_email, EmailTeam.is_personal.is_(True), EmailTeam.is_active.is_(True)).first()
            return team

        except Exception as e:
            logger.error(f"Failed to get personal team for {user_email}: {e}")
            return None

    async def ensure_personal_team(self, user: EmailUser) -> Optional[EmailTeam]:
        """Ensure a user has a personal team, creating one if needed.

        Args:
            user: EmailUser instance

        Returns:
            EmailTeam: The user's personal team (existing or newly created), or None if auto-creation is disabled

        Raises:
            Exception: If team creation or retrieval fails

        Examples:
            >>> import asyncio
            >>> from unittest.mock import Mock
            >>> service = PersonalTeamService(Mock())
            >>> asyncio.iscoroutinefunction(service.ensure_personal_team)
            True
        """
        try:
            # Try to get existing personal team
            team = await self.get_personal_team(user.email)

            if team is None:
                if not getattr(settings, "auto_create_personal_teams", True):
                    return None
                # Create personal team if it doesn't exist
                logger.info(f"Creating missing personal team for user {user.email}")
                team = await self.create_personal_team(user)

            return team

        except ValueError:
            # User already has a team, get it
            team = await self.get_personal_team(user.email)
            if team is None:
                raise Exception(f"Failed to get or create personal team for {user.email}")
            return team

    def is_personal_team(self, team_id: str) -> bool:
        """Check if a team is a personal team.

        Args:
            team_id: ID of the team to check

        Returns:
            bool: True if the team is a personal team, False otherwise

        Examples:
            >>> from unittest.mock import Mock
            >>> service = PersonalTeamService(Mock())
            >>> callable(service.is_personal_team)
            True
        """
        try:
            team = self.db.query(EmailTeam).filter(EmailTeam.id == team_id, EmailTeam.is_active.is_(True)).first()
            return team is not None and team.is_personal

        except Exception as e:
            logger.error(f"Failed to check if team {team_id} is personal: {e}")
            return False

    async def delete_personal_team(self, team_id: str) -> bool:
        """Delete a personal team (not allowed).

        Personal teams cannot be deleted, only deactivated.

        Args:
            team_id: ID of the team to delete

        Returns:
            bool: False (personal teams cannot be deleted)

        Raises:
            ValueError: Always, as personal teams cannot be deleted

        Examples:
            >>> import asyncio
            >>> from unittest.mock import Mock
            >>> service = PersonalTeamService(Mock())
            >>> asyncio.iscoroutinefunction(service.delete_personal_team)
            True
        """
        if self.is_personal_team(team_id):
            raise ValueError("Personal teams cannot be deleted")
        return False

    async def get_personal_team_owner(self, team_id: str) -> Optional[str]:
        """Get the owner email of a personal team.

        Args:
            team_id: ID of the personal team

        Returns:
            str: Owner email address or None if not found

        Examples:
            Used for access control and team management operations.
        """
        try:
            team = self.db.query(EmailTeam).filter(EmailTeam.id == team_id, EmailTeam.is_personal.is_(True), EmailTeam.is_active.is_(True)).first()
            return team.created_by if team else None

        except Exception as e:
            logger.error(f"Failed to get personal team owner for {team_id}: {e}")
            return None
