# shared/clients/auth_client.py
"""
Auth Service Client for Inter-Service Communication
Provides methods to interact with the authentication/onboarding service
"""

from typing import Optional, Dict, Any, List
import structlog

from shared.clients.base_service_client import BaseServiceClient
from shared.config.base import BaseServiceSettings

logger = structlog.get_logger()


class AuthServiceClient(BaseServiceClient):
    """Client for interacting with the Auth Service"""

    def __init__(self, config: BaseServiceSettings):
        super().__init__("auth", config)

    def get_service_base_path(self) -> str:
        """Return the base path for auth service APIs"""
        return "/api/v1/auth"

    async def get_user_onboarding_progress(self, user_id: str) -> Optional[Dict[str, Any]]:
        """
        Get user's onboarding progress including step data

        Args:
            user_id: User ID to fetch progress for

        Returns:
            Dict with user progress including steps with data, or None if failed
        """
        try:
            # Use the service endpoint that accepts user_id as parameter
            result = await self.get(f"/users/{user_id}/onboarding/progress")

            if result:
                logger.info("Retrieved user onboarding progress",
                           user_id=user_id,
                           current_step=result.get("current_step"))
                return result
            else:
                logger.warning("No onboarding progress found",
                             user_id=user_id)
                return None

        except Exception as e:
            logger.error("Failed to get user onboarding progress",
                        user_id=user_id,
                        error=str(e))
            return None

    async def get_user_step_data(self, user_id: str, step_name: str) -> Optional[Dict[str, Any]]:
        """
        Get data for a specific onboarding step

        Args:
            user_id: User ID
            step_name: Name of the step (e.g., "user_registered")

        Returns:
            Step data dictionary or None if not found
        """
        try:
            progress = await self.get_user_onboarding_progress(user_id)

            if not progress:
                logger.warning("No progress data returned",
                             user_id=user_id)
                return None

            logger.debug("Retrieved progress data",
                        user_id=user_id,
                        steps_count=len(progress.get("steps", [])),
                        current_step=progress.get("current_step"))

            # Find the specific step
            for step in progress.get("steps", []):
                if step.get("step_name") == step_name:
                    step_data = step.get("data", {})
                    logger.info("Found step data",
                               user_id=user_id,
                               step_name=step_name,
                               data_keys=list(step_data.keys()) if step_data else [],
                               has_subscription_plan="subscription_plan" in step_data)
                    return step_data

            logger.warning("Step not found in progress",
                         user_id=user_id,
                         step_name=step_name,
                         available_steps=[s.get("step_name") for s in progress.get("steps", [])])
            return None

        except Exception as e:
            logger.error("Failed to get step data",
                        user_id=user_id,
                        step_name=step_name,
                        error=str(e))
            return None

    async def get_subscription_plan_from_registration(self, user_id: str) -> str:
        """
        Get the subscription plan selected during user registration

        Args:
            user_id: User ID

        Returns:
            Plan name (e.g., "starter", "professional", "enterprise") or "starter" as default
        """
        try:
            step_data = await self.get_user_step_data(user_id, "user_registered")

            if step_data and "subscription_plan" in step_data:
                plan = step_data["subscription_plan"]
                logger.info("Retrieved subscription plan from registration",
                           user_id=user_id,
                           plan=plan)
                return plan
            else:
                logger.info("No subscription plan in registration data, using default",
                           user_id=user_id,
                           default_plan="starter")
                return "starter"

        except Exception as e:
            logger.warning("Failed to retrieve subscription plan, using default",
                         user_id=user_id,
                         error=str(e),
                         default_plan="starter")
            return "starter"

    async def create_user_by_owner(self, user_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        Create a new user account via the auth service (owner/admin only - pilot phase).

        This method calls the auth service endpoint that allows tenant owners
        to directly create users with passwords during the pilot phase.

        Args:
            user_data: Dictionary containing:
                - email: User email (required)
                - full_name: Full name (required)
                - password: Password (required)
                - phone: Phone number (optional)
                - role: User role (optional, default: "user")
                - language: Language preference (optional, default: "es")
                - timezone: Timezone (optional, default: "Europe/Madrid")

        Returns:
            Dict with created user data including user ID

        Raises:
            Exception if user creation fails
        """
        try:
            logger.info(
                "Creating user via auth service",
                email=user_data.get("email"),
                role=user_data.get("role", "user")
            )

            result = await self.post("/users/create-by-owner", user_data)

            if result and result.get("id"):
                logger.info(
                    "User created successfully via auth service",
                    user_id=result.get("id"),
                    email=result.get("email")
                )
                return result
            else:
                logger.error("User creation returned no user ID")
                raise Exception("User creation failed: No user ID returned")

        except Exception as e:
            logger.error(
                "Failed to create user via auth service",
                email=user_data.get("email"),
                error=str(e)
            )
            raise

    async def get_user_details(self, user_id: str) -> Optional[Dict[str, Any]]:
        """
        Get detailed user information including payment details

        Args:
            user_id: User ID to fetch details for

        Returns:
            Dict with user details including:
            - id, email, full_name, is_active, is_verified
            - phone, language, timezone, role
            - payment_customer_id, default_payment_method_id
            - created_at, last_login, etc.
            Returns None if user not found or request fails
        """
        try:
            logger.info("Fetching user details from auth service",
                       user_id=user_id)

            result = await self.get(f"/users/{user_id}")

            if result and result.get("id"):
                logger.info("Successfully retrieved user details",
                           user_id=user_id,
                           email=result.get("email"),
                           has_payment_info="payment_customer_id" in result)
                return result
            else:
                logger.warning("No user details found",
                             user_id=user_id)
                return None

        except Exception as e:
            logger.error("Failed to get user details from auth service",
                        user_id=user_id,
                        error=str(e))
            return None

    async def update_user_tenant_id(self, user_id: str, tenant_id: str) -> bool:
        """
        Update the user's tenant_id after tenant registration

        Args:
            user_id: User ID to update
            tenant_id: Tenant ID to link to the user

        Returns:
            True if successful, False otherwise
        """
        try:
            logger.info("Updating user tenant_id",
                       user_id=user_id,
                       tenant_id=tenant_id)

            result = await self.patch(
                f"/users/{user_id}/tenant",
                {"tenant_id": tenant_id}
            )

            if result:
                logger.info("Successfully updated user tenant_id",
                           user_id=user_id,
                           tenant_id=tenant_id)
                return True
            else:
                logger.warning("Failed to update user tenant_id",
                             user_id=user_id,
                             tenant_id=tenant_id)
                return False

        except Exception as e:
            logger.error("Error updating user tenant_id",
                        user_id=user_id,
                        tenant_id=tenant_id,
                        error=str(e))
            return False

