# 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 Schemas for CLI

This module provides Pydantic models for auto-link operations using the v4 API
with clean, modern data contracts and proper validation.
"""

from datetime import UTC, datetime
from typing import Literal

from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator


class AutoLinkConfiguration(BaseModel):
    """Auto-link configuration for a connection."""

    role_name: str | None = Field(None, description="IAM role name for auto-link (None if not configured)")
    enabled: bool = Field(default=False, description="Whether auto-link is enabled")
    last_run: datetime | None = Field(None, description="Last auto-link run timestamp")
    next_run: datetime | None = Field(None, description="Next scheduled auto-link run")

    # Link tracking
    linked_accounts: list[str] = Field(default_factory=list, description="Successfully linked account IDs")
    failed_accounts: list[str] = Field(default_factory=list, description="Account IDs that failed to link")
    ignored_accounts: list[str] = Field(default_factory=list, description="Account IDs to ignore")

    # Statistics
    total_discovered: int | None = Field(None, description="Total accounts discovered (None if not available)")
    total_linked: int = Field(default=0, description="Total accounts successfully linked")
    total_failed: int = Field(default=0, description="Total accounts that failed to link")

    # Metadata
    created: datetime | None = Field(None, description="Configuration creation timestamp")
    updated_at: datetime | None = Field(None, description="Last configuration update timestamp")

    model_config = ConfigDict(extra="allow")


class ConnectionAutoLinkStatus(BaseModel):
    """Auto-link status for a specific connection."""

    connection_id: str = Field(..., description="Connection identifier")
    cz_organization_id: str = Field(..., description="Organization identifier")
    connection_name: str | None = Field(None, description="Connection display name")
    provider: str = Field(..., description="Cloud provider (AWS, GCP, AZURE, SNOWFLAKE, etc.)")
    account_type: str | None = Field(None, description="Account type (payer, resource, etc.)")

    # Auto-link configuration
    auto_link: AutoLinkConfiguration | None = Field(None, description="Auto-link configuration")
    auto_link_enabled: bool = Field(default=False, description="Whether auto-link is enabled")

    # Health and status
    is_healthy: bool = Field(default=True, description="Whether the connection is healthy")
    last_checked: datetime | None = Field(None, description="Last health check timestamp")

    model_config = ConfigDict(extra="allow")


class OrganizationAutoLinkStatus(BaseModel):
    """Auto-link status for an organization."""

    cz_organization_id: str = Field(..., description="Organization identifier")
    cz_organization_name: str | None = Field(None, description="Organization display name")

    # Connection summaries
    total_connections: int = Field(default=0, description="Total connections in organization")
    auto_link_enabled_connections: dict[str, ConnectionAutoLinkStatus] = Field(
        default_factory=dict, description="Connections with auto-link enabled"
    )
    # Statistics
    total_auto_link_enabled: int = Field(default=0, description="Total connections with auto-link enabled")
    total_linked_accounts: int = Field(default=0, description="Total linked accounts across all connections")
    total_failed_accounts: int = Field(default=0, description="Total failed accounts across all connections")
    total_ignored_accounts: int = Field(default=0, description="Total ignored accounts across all connections")

    # Timestamps
    last_updated: datetime | None = Field(None, description="Last status update timestamp")

    model_config = ConfigDict(extra="allow")


class EnableAutoLinkRequest(BaseModel):
    """Request model for enabling auto-link."""

    role_name: str = Field(..., min_length=1, max_length=255, description="IAM role name for auto-link")
    force: bool = Field(default=False, description="Force enable even if already enabled")

    @field_validator("role_name")
    @classmethod
    def validate_role_name(cls, v):
        if not v or not v.strip():
            raise ValueError("Role name cannot be empty")
        return v.strip()


class DisableAutoLinkRequest(BaseModel):
    """Request model for disabling auto-link."""

    force: bool = Field(default=False, description="Force disable even if already disabled")


class UpdateIgnoreListRequest(BaseModel):
    """Request model for updating auto-link ignore list."""

    ignore_list: list[str] = Field(..., min_length=1, description="Account IDs to ignore")
    action: str = Field(default="add", description="Action to perform: 'add', 'remove', or 'replace'")

    @field_validator("ignore_list")
    @classmethod
    def validate_ignore_list(cls, v):
        if not v:
            raise ValueError("Ignore list cannot be empty")
        # Remove duplicates and empty strings
        cleaned = [item.strip() for item in v if item and item.strip()]
        if not cleaned:
            raise ValueError("Ignore list must contain at least one valid account ID")
        return cleaned

    @field_validator("action")
    @classmethod
    def validate_action(cls, v):
        if v not in ["add", "remove", "replace"]:
            raise ValueError('Action must be "add", "remove", or "replace"')
        return v


class TriageFailuresRequest(BaseModel):
    """Request model for triaging auto-link failures."""

    action: Literal["ignore", "retry", "retry_all"] = Field(..., description="Triage action to perform")
    account_ids: list[str] | None = Field(None, description="Account IDs to triage (required for ignore/retry)")

    @field_validator("account_ids", mode="before")
    @classmethod
    def validate_account_ids(cls, v):
        """Strip whitespace and remove empty entries."""
        if v is None:
            return v
        cleaned = [item.strip() for item in v if item and item.strip()]
        if not cleaned:
            return None
        return cleaned

    @model_validator(mode="after")
    def validate_action_account_ids(self):
        """Validate that account_ids is provided for ignore/retry and forbidden for retry_all."""
        if self.action in ("ignore", "retry"):
            if not self.account_ids:
                raise ValueError(f"account_ids is required for action '{self.action}'")
        elif self.action == "retry_all":
            if self.account_ids:
                raise ValueError("account_ids must not be provided for action 'retry_all'")
        return self


class ConnectionFailureSummary(BaseModel):
    """Per-connection failure statistics for organization analysis."""

    connection_id: str = Field(..., description="Connection identifier")
    connection_name: str | None = Field(None, description="Connection display name")
    total_failed: int = Field(default=0, description="Total accounts in link_failure")
    total_ignored: int = Field(default=0, description="Total accounts in ignore list")
    total_linked: int = Field(default=0, description="Total accounts successfully linked")
    failed_account_ids: list[str] = Field(default_factory=list, description="Account IDs in link_failure")


class AccountFailureDetail(BaseModel):
    """Cross-connection failure detail for an account."""

    account_id: str = Field(..., description="AWS account ID")
    connections: list[str] = Field(default_factory=list, description="Connection IDs where this account fails")
    failure_count: int = Field(default=0, description="Number of connections where this account fails")


class OrganizationFailureAnalysis(BaseModel):
    """Organization-level failure analysis response."""

    cz_organization_id: str = Field(..., description="Organization identifier")
    total_connections_analyzed: int = Field(default=0, description="Total auto-link-enabled connections analyzed")
    total_unique_failed_accounts: int = Field(default=0, description="Total unique accounts failing across connections")
    accounts_failing_all_connections: list[AccountFailureDetail] = Field(
        default_factory=list, description="Accounts failing in every connection (when 2+ connections)"
    )
    accounts_failing_multiple: list[AccountFailureDetail] = Field(
        default_factory=list, description="Accounts failing in 2+ connections but not all"
    )
    per_connection_summary: list[ConnectionFailureSummary] = Field(
        default_factory=list, description="Per-connection failure breakdown"
    )
    timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC), description="Analysis timestamp")

    model_config = ConfigDict(extra="allow")


class AutoLinkActionResponse(BaseModel):
    """Response model for auto-link actions."""

    connection_id: str = Field(..., description="Connection identifier")
    action: str = Field(..., description="Action performed")
    success: bool = Field(..., description="Whether the action was successful")
    message: str = Field(..., description="Success or error message")
    auto_link_enabled: bool = Field(..., description="Current auto-link enabled status")
    auto_link_configuration: AutoLinkConfiguration | None = Field(None, description="Updated auto-link configuration")
    timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC), description="Response timestamp")

    model_config = ConfigDict(extra="allow")
