# Copyright (c) CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
#

"""
Auto-link API V4 Client

This module provides client functions for auto-link management using the v4 API
with Okta authentication and Pydantic models for clean data contracts.
"""

import httpx

from src.api.authenticated import get_authenticated, post_authenticated
from src.exceptions import CzOpsApiException
from src.schemas.autolink import (
    AutoLinkConfiguration,
    ConnectionAutoLinkStatus,
    DisableAutoLinkRequest,
    EnableAutoLinkRequest,
    OrganizationAutoLinkStatus,
    UpdateIgnoreListRequest,
)


def get_connection_auto_link_status_v4(connection_id: str, debug: bool = False) -> ConnectionAutoLinkStatus:
    """
    Get auto-link status for a specific connection using V4 API.

    Args:
        connection_id (str): Connection ID to check
        debug (bool): Whether to print debug information

    Returns:
        ConnectionAutoLinkStatus: Auto-link status information

    Raises:
        CzOpsApiException: If the API request fails
    """
    endpoint = f"auto-link/connection/{connection_id}/status"

    try:
        response = get_authenticated(endpoint, debug=debug)
        return ConnectionAutoLinkStatus(**response)
    except httpx.HTTPError as e:
        raise CzOpsApiException(f"Failed to get connection auto-link status: {str(e)}") from e


def get_organization_auto_link_status_v4(organization_id: str, debug: bool = False) -> OrganizationAutoLinkStatus:
    """
    Get auto-link status for all connections in an organization using V4 API.

    Args:
        organization_id (str): Organization ID to check
        debug (bool): Whether to print debug information

    Returns:
        OrganizationAutoLinkStatus: Auto-link status for all connections

    Raises:
        CzOpsApiException: If the API request fails
    """

    endpoint = f"auto-link/organization/{organization_id}/status"

    try:
        response = get_authenticated(endpoint, debug=debug)

        # Check if the response contains an error field
        if isinstance(response, dict) and "error" in response:
            error_msg = response.get("error", "Unknown error")
            details = response.get("details", "")
            raise CzOpsApiException(f"Auto-link status API error: {error_msg}. {details}")

        return OrganizationAutoLinkStatus(**response)
    except httpx.HTTPError as e:
        raise CzOpsApiException(f"Failed to get organization auto-link status: {str(e)}") from e
    except CzOpsApiException:
        # Re-raise our own exceptions
        raise
    except Exception as e:
        # Handle validation errors and other unexpected errors
        raise CzOpsApiException(f"Failed to parse organization auto-link status: {str(e)}") from e


def enable_connection_auto_link_v4(connection_id: str, role_name: str, force: bool = False) -> dict | None:
    """
    Enable auto-link for a connection using V4 API.

    Args:
        connection_id (str): Connection ID to enable auto-link for
        role_name (str): IAM role name for auto-link
        force (bool): Force enable even if already enabled

    Returns:
        AutoLinkActionResponse: Response with updated configuration

    Raises:
        CzOpsApiException: If the API request fails
    """
    endpoint = f"auto-link/connection/{connection_id}/enable"
    request_data = EnableAutoLinkRequest(role_name=role_name, force=force)

    try:
        response = post_authenticated(endpoint, json_data=request_data.model_dump())
        return response
    except httpx.HTTPError as e:
        raise CzOpsApiException(f"Failed to enable auto-link: {str(e)}") from e


def disable_connection_auto_link_v4(connection_id: str, force: bool = False) -> dict | None:
    """
    Disable auto-link for a connection using V4 API.

    Args:
        connection_id (str): Connection ID to disable auto-link for
        force (bool): Force disable even if already disabled

    Returns:
        AutoLinkActionResponse: Response with updated configuration

    Raises:
        CzOpsApiException: If the API request fails
    """
    endpoint = f"auto-link/connection/{connection_id}/disable"

    request_data = DisableAutoLinkRequest(force=force)

    try:
        response = post_authenticated(endpoint, json_data=request_data.model_dump())
        return response
    except httpx.HTTPError as e:
        raise CzOpsApiException(f"Failed to disable auto-link: {str(e)}") from e


def update_connection_auto_link_ignore_list_v4(
    connection_id: str, ignore_list: list[str], action: str = "add"
) -> dict | None:
    """
    Update auto-link ignore list for a connection using V4 API.

    Args:
        connection_id (str): Connection ID to update ignore list for
        ignore_list (List[str]): Account IDs to ignore
        action (str): Action to perform ('add', 'remove', 'replace')

    Returns:
        AutoLinkActionResponse: Response with updated configuration

    Raises:
        CzOpsApiException: If the API request fails
    """
    endpoint = f"auto-link/connection/{connection_id}/ignore-list"

    request_data = UpdateIgnoreListRequest(ignore_list=ignore_list, action=action)

    try:
        response = post_authenticated(endpoint, json_data=request_data.model_dump())
        return response
    except httpx.HTTPError as e:
        raise CzOpsApiException(f"Failed to update auto-link ignore list: {str(e)}") from e


# Utility functions for CLI integration


def display_auto_link_configuration(config: AutoLinkConfiguration | None) -> str:
    """
    Format auto-link configuration for display.

    Args:
        config (Optional[AutoLinkConfiguration]): Auto-link configuration to display

    Returns:
        str: Formatted configuration display
    """
    if not config:
        return "Auto-link: Not configured"

    status = "Enabled" if config.enabled else "Disabled"
    lines = [f"Auto-link: {status}", f"Role Name: {config.role_name}"]

    if config.last_run:
        lines.append(f"Last Run: {config.last_run.isoformat()}")

    if config.next_run:
        lines.append(f"Next Run: {config.next_run.isoformat()}")

    # Statistics
    if config.total_discovered > 0 or config.total_linked > 0 or config.total_failed > 0:
        lines.extend(
            [
                "",
                "Statistics:",
                f"  Discovered: {config.total_discovered}",
                f"  Linked: {config.total_linked}",
                f"  Failed: {config.total_failed}",
                f"  Ignored: {len(config.ignored_accounts)}",
            ]
        )

    # Account lists (only show first few for brevity)
    if config.linked_accounts:
        display_linked = config.linked_accounts[:3]
        suffix = f" (+{len(config.linked_accounts) - 3} more)" if len(config.linked_accounts) > 3 else ""
        lines.append(f"Linked Accounts: {', '.join(display_linked)}{suffix}")

    if config.failed_accounts:
        display_failed = config.failed_accounts[:3]
        suffix = f" (+{len(config.failed_accounts) - 3} more)" if len(config.failed_accounts) > 3 else ""
        lines.append(f"Failed Accounts: {', '.join(display_failed)}{suffix}")

    if config.ignored_accounts:
        display_ignored = config.ignored_accounts[:3]
        suffix = f" (+{len(config.ignored_accounts) - 3} more)" if len(config.ignored_accounts) > 3 else ""
        lines.append(f"Ignored Accounts: {', '.join(display_ignored)}{suffix}")

    return "\n".join(lines)


def display_connection_auto_link_status(status: ConnectionAutoLinkStatus) -> str:
    """
    Format connection auto-link status for display.

    Args:
        status (ConnectionAutoLinkStatus): Connection auto-link status to display

    Returns:
        str: Formatted status display
    """
    lines = [
        f"Connection: {status.connection_name or status.connection_id}",
        f"Provider: {status.provider}",
        f"Organization: {status.cz_organization_id}",
    ]

    if status.account_type:
        lines.append(f"Account Type: {status.account_type}")

    lines.append(f"Health Status: {'Healthy' if status.is_healthy else 'Unhealthy'}")
    lines.append("")
    lines.append(display_auto_link_configuration(status.auto_link))

    return "\n".join(lines)


def display_organization_auto_link_status(status: OrganizationAutoLinkStatus) -> str:
    """
    Format organization auto-link status for display.

    Args:
        status (OrganizationAutoLinkStatus): Organization auto-link status to display

    Returns:
        str: Formatted status display
    """
    lines = [
        f"Organization: {status.cz_organization_name or status.cz_organization_id}",
        f"Total Connections: {status.total_connections}",
        f"Auto-link Enabled: {status.total_auto_link_enabled}",
        "",
        "Summary Statistics:",
        f"  Total Linked Accounts: {status.total_linked_accounts}",
        f"  Total Failed Accounts: {status.total_failed_accounts}",
        f"  Total Ignored Accounts: {status.total_ignored_accounts}",
        "",
    ]

    if status.auto_link_enabled_connections:
        lines.append("Auto-link Enabled Connections:")
        for connection_id, conn_status in status.auto_link_enabled_connections.items():
            connection_name = conn_status.connection_name or connection_id
            if conn_status.auto_link:
                linked_count = len(conn_status.auto_link.linked_accounts)
                failed_count = len(conn_status.auto_link.failed_accounts)
                lines.append(f"  {connection_name}: {linked_count} linked, {failed_count} failed")
            else:
                lines.append(f"  {connection_name}: No auto-link data")

    if status.last_updated:
        lines.extend(["", f"Last Updated: {status.last_updated.isoformat()}"])

    return "\n".join(lines)
