# 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
#

"""
V4 Healthcheck API Client

This module provides a clean, modern interface for healthcheck operations using the v4 API
with Okta authentication. Single-shot healthcheck APIs only:
- get_organization_healthcheck(organization_id) -> returns OrganizationHealthcheck
- get_connection_healthcheck(connection_id) -> returns ConnectionHealthcheck
- get_healthcheck_status() -> returns HealthcheckStatusResponse

API Documentation:
- API Endpoints: cz-ops-services/docs/api/healthcheck.md
- Data Model/Contract: cz-ops-services/docs/api/healthcheck_data_model.md

Note: Some documented stable metadata fields (cz_organization_id, cz_organization_name)
may not be returned by the backend. The CLI handles this by making those fields optional
and enriching from connection data when available.
"""

from typing import Any

from pydantic import BaseModel, ConfigDict, Field, ValidationError
from rich.console import Console

from src.api.authenticated import get_authenticated, post_authenticated
from src.api.v4_organizations import DictAccessModel
from src.exceptions import APIError

console = Console()


# V4 Pydantic Models - Based on stable API contract from healthcheck_data_model.md


class HealthCheck(DictAccessModel):
    """Individual health check result.

    Stable fields per API contract: name, status, message, duration_ms, timestamp
    The details object structure may change - use for display/debugging only.
    """

    name: str = Field(..., description="Check identifier (e.g., 'permissions_check')")
    status: str = Field(..., description="Check status: healthy, degraded, unhealthy, warning, unknown")
    message: str = Field(..., description="Human-readable status message")
    duration_ms: float = Field(..., description="Check execution time in milliseconds")
    timestamp: str = Field(..., description="ISO 8601 timestamp")
    details: dict[str, Any] = Field(default_factory=dict, description="Check-specific details (structure varies)")

    model_config = ConfigDict(extra="allow")


class HealthcheckSummary(DictAccessModel):
    """Summary of health checks - stable contract fields."""

    total_checks: int = Field(0, description="Total number of checks performed")
    healthy_count: int = Field(0, description="Number of checks with 'healthy' status")
    degraded_count: int = Field(0, description="Number of checks with 'degraded' status")
    unhealthy_count: int = Field(0, description="Number of checks with 'unhealthy' status")
    warning_count: int = Field(0, description="Number of checks with 'warning' status")
    unknown_count: int = Field(0, description="Number of checks with 'unknown' status")

    model_config = ConfigDict(extra="allow")


class ConnectionMetadata(DictAccessModel):
    """Connection metadata from healthcheck response.

    Stable contract fields per API docs:
    - connection_id, connection_name, cz_organization_id, cz_organization_name
    - cloud_provider, last_updated, connection_type, connection_types

    Note: Backend may not return cz_organization_id/cz_organization_name.
    The CLI enriches missing org info from connection data when available.
    """

    # Connection identifiers
    connection_id: str | None = Field(None, description="Connection identifier")
    connection_name: str | None = Field(None, description="Human-readable connection name")

    # Organization info - may not be returned by backend, enriched by CLI when available
    cz_organization_id: str | None = Field(None, description="CloudZero organization UUID")
    cz_organization_name: str | None = Field(None, description="Organization name")

    # Provider and type info
    cloud_provider: str = Field("aws", description="Cloud provider (e.g., 'aws')")
    connection_type: str | None = Field(None, description="Specific type if filtered")
    connection_types: list[str] = Field(default_factory=list, description="All connection types")

    # Timestamps
    last_updated: str | None = Field(None, description="ISO 8601 timestamp of last data update")

    model_config = ConfigDict(extra="allow")


class ConnectionHealthcheck(DictAccessModel):
    """Connection healthcheck response - stable contract per API docs."""

    connection_id: str = Field(..., description="AWS account ID or connection identifier")
    status: str = Field(..., description="Overall health status: healthy, degraded, unhealthy, warning, unknown")
    overall_score: float = Field(..., description="Health score 0-100")
    duration_ms: float = Field(..., description="Total check duration in milliseconds")
    timestamp: str = Field(..., description="ISO 8601 timestamp")
    success: bool = Field(..., description="Whether healthcheck completed successfully")
    checks: list[HealthCheck] = Field(default_factory=list, description="Array of individual check results")
    summary: HealthcheckSummary = Field(..., description="Summary statistics for checks")
    metadata: ConnectionMetadata = Field(..., description="Connection metadata")
    error: str | None = Field(None, description="Present only on failures")

    model_config = ConfigDict(extra="allow")


class OrganizationSummary(DictAccessModel):
    """Organization health summary statistics."""

    total_connections: int = Field(..., description="Total connections in org")
    healthy_count: int = Field(..., description="Connections with 'healthy' status")
    degraded_count: int = Field(0, description="Connections with 'degraded' status")
    unhealthy_count: int = Field(..., description="Connections with 'unhealthy' status")
    warning_count: int = Field(..., description="Connections with 'warning' status")
    unknown_count: int = Field(..., description="Connections with 'unknown' status")

    model_config = ConfigDict(extra="allow")


class OrganizationHealthcheck(DictAccessModel):
    """Organization healthcheck response as documented in API."""

    organization_id: str = Field(..., description="CloudZero organization UUID")
    status: str = Field(..., description="Overall org health status")
    overall_score: float = Field(..., description="Aggregate health score 0-100")
    duration_ms: float = Field(..., description="Total check duration")
    timestamp: str = Field(..., description="ISO 8601 timestamp")
    success: bool = Field(..., description="Whether check completed")
    summary: OrganizationSummary = Field(..., description="Summary statistics")
    connections: list[ConnectionHealthcheck] = Field(default_factory=list, description="Connection health results")
    error: str | None = Field(None, description="Present only on failures")

    model_config = ConfigDict(extra="allow")


class BulkHealthSummary(DictAccessModel):
    """Bulk health check summary statistics."""

    checked_entities: int = Field(..., description="Number of entities checked")
    healthy_count: int = Field(0, description="Entities with 'healthy' status")
    unhealthy_count: int = Field(0, description="Entities with 'unhealthy' status")
    warning_count: int = Field(0, description="Entities with 'warning' status")
    unknown_count: int = Field(0, description="Entities with 'unknown' status")
    success_rate: float = Field(0, description="Percentage 0-100")
    duration_ms: float = Field(0, description="Total check duration in milliseconds")

    model_config = ConfigDict(extra="allow")


class BulkHealthResult(DictAccessModel):
    """Individual result within a bulk healthcheck response."""

    entity_id: str = Field(..., description="Connection or organization ID")
    status: str = Field(..., description="Health status")
    score: float = Field(0, description="Health score 0-100")
    checks: list[HealthCheck] = Field(default_factory=list, description="Check results (if include_details=true)")

    model_config = ConfigDict(extra="allow")


class BulkHealthcheckResponse(DictAccessModel):
    """Bulk healthcheck response - stable contract per API docs."""

    entity_type: str = Field(..., description="'connection' or 'organization'")
    timestamp: str = Field(..., description="ISO 8601 timestamp")
    summary: BulkHealthSummary = Field(..., description="Summary statistics")
    results: list[BulkHealthResult] = Field(default_factory=list, description="Health results per entity")

    model_config = ConfigDict(extra="allow")


class HealthcheckSystem(BaseModel):
    """Healthcheck system information."""

    status: str = Field(..., description="System status")
    version: str = Field(..., description="System version")
    uptime_hours: float = Field(..., description="System uptime in hours")
    last_restart: str = Field(..., description="Last restart timestamp")

    model_config = ConfigDict(extra="allow")


class HealthcheckStatistics(BaseModel):
    """Healthcheck system statistics."""

    total_checks_today: int = Field(..., description="Total checks performed today")
    average_response_time_ms: float = Field(..., description="Average response time")
    success_rate_percentage: float = Field(..., description="Success rate percentage")

    model_config = ConfigDict(extra="allow")


class HealthcheckStatusResponse(BaseModel):
    """Healthcheck system status response as documented in API."""

    healthcheck_system: HealthcheckSystem = Field(..., description="System information")
    capabilities: list[str] = Field(..., description="System capabilities")
    statistics: HealthcheckStatistics = Field(..., description="System statistics")
    timestamp: str = Field(..., description="Response timestamp")
    success: bool = Field(..., description="Whether the status check succeeded")

    model_config = ConfigDict(extra="allow")


# API Client Functions


def get_organization_healthcheck(
    organization_id: str, include_details: bool = True, debug: bool = False
) -> OrganizationHealthcheck:
    """
    Get organization healthcheck using v4 API.

    Args:
        organization_id: Organization identifier
        include_details: Whether to include detailed health information
        debug: Whether to show debug information

    Returns:
        OrganizationHealthcheck: Organization health status and connection details

    Raises:
        APIError: If the API request fails
        ValueError: If the response format is invalid
    """
    if debug:
        console.print(f"[cyan]DEBUG: Fetching organization healthcheck via V4 API for {organization_id}[/]")

    try:
        # Build query parameters
        params = {}
        if not include_details:
            params["include_details"] = "false"

        # Make authenticated request to v4 organization healthcheck endpoint
        response_data = get_authenticated(
            endpoint_path=f"healthcheck/organization/{organization_id}", params=params, debug=debug
        )

        if debug:
            console.print(f"[cyan]DEBUG: Raw API response: {response_data}[/]")

        # Validate response with Pydantic model
        return OrganizationHealthcheck(**response_data)

    except APIError:
        # Re-raise API errors as-is
        raise
    except ValidationError as e:
        if debug:
            console.print(f"[red]DEBUG: Response validation failed: {e}[/]")
        raise APIError(f"Invalid response format from v4 API: {e}") from e
    except Exception as e:
        error_msg = f"Failed to get organization healthcheck: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def get_connection_healthcheck(
    connection_id: str,
    include_details: bool = True,
    connection_type: str | None = None,
    debug: bool = False,
) -> ConnectionHealthcheck:
    """
    Get connection healthcheck using v4 API.

    Args:
        connection_id: Connection identifier
        include_details: Whether to include detailed health information
        connection_type: Optional type filter — one of COST, RESOURCE, METRICS, DATA
        debug: Whether to show debug information

    Returns:
        ConnectionHealthcheck: Connection health status and details

    Raises:
        APIError: If the API request fails
        ValueError: If the response format is invalid
    """
    if debug:
        console.print(f"[cyan]DEBUG: Fetching connection healthcheck via V4 API for {connection_id}[/]")

    try:
        # Build query parameters
        params = {}
        if not include_details:
            params["include_details"] = "false"
        if connection_type:
            params["type"] = connection_type

        # Make authenticated request to v4 connection healthcheck endpoint
        response_data = get_authenticated(
            endpoint_path=f"healthcheck/connection/{connection_id}", params=params, debug=debug
        )

        if debug:
            console.print(f"[cyan]DEBUG: Raw API response: {response_data}[/]")

        # Validate response with Pydantic model
        return ConnectionHealthcheck(**response_data)

    except APIError:
        # Re-raise API errors as-is
        raise
    except ValidationError as e:
        if debug:
            console.print(f"[red]DEBUG: Response validation failed: {e}[/]")
        raise APIError(f"Invalid response format from v4 API: {e}") from e
    except Exception as e:
        error_msg = f"Failed to get connection healthcheck: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def get_healthcheck_status(debug: bool = False) -> HealthcheckStatusResponse:
    """
    Get healthcheck system status using v4 API.

    Args:
        debug: Whether to show debug information

    Returns:
        HealthcheckStatusResponse: Healthcheck system status

    Raises:
        APIError: If the API request fails
        ValueError: If the response format is invalid
    """
    if debug:
        console.print("[cyan]DEBUG: Fetching healthcheck system status via V4 API[/]")

    try:
        # Make authenticated request to v4 healthcheck status endpoint
        response_data = get_authenticated(endpoint_path="healthcheck/status", debug=debug)

        if debug:
            console.print(f"[cyan]DEBUG: Raw API response: {response_data}[/]")

        # Validate response with Pydantic model
        return HealthcheckStatusResponse(**response_data)

    except APIError:
        # Re-raise API errors as-is
        raise
    except ValidationError as e:
        if debug:
            console.print(f"[red]DEBUG: Response validation failed: {e}[/]")
        raise APIError(f"Invalid response format from v4 API: {e}") from e
    except Exception as e:
        error_msg = f"Failed to get healthcheck system status: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def get_bulk_healthcheck(
    entity_ids: list[str],
    entity_type: str = "connection",
    include_details: bool = True,
    debug: bool = False,
) -> BulkHealthcheckResponse:
    """
    Check health status for multiple entities in a single request.

    Args:
        entity_ids: List of connection or organization IDs to check
        entity_type: Type of entities - "connection" or "organization"
        include_details: Include detailed check results (default: true)
        debug: Whether to show debug information

    Returns:
        BulkHealthcheckResponse: Bulk health check results

    Raises:
        APIError: If the API request fails
    """
    if debug:
        console.print(f"[cyan]DEBUG: Fetching bulk healthcheck via V4 API for {len(entity_ids)} {entity_type}s[/]")

    try:
        json_data = {
            "entity_ids": entity_ids,
            "entity_type": entity_type,
            "include_details": include_details,
        }

        response_data = post_authenticated(endpoint_path="healthcheck/bulk", json_data=json_data, debug=debug)

        if debug:
            console.print(f"[cyan]DEBUG: Raw API response: {response_data}[/]")

        return BulkHealthcheckResponse(**response_data)

    except APIError:
        raise
    except ValidationError as e:
        if debug:
            console.print(f"[red]DEBUG: Response validation failed: {e}[/]")
        raise APIError(f"Invalid response format from v4 API: {e}") from e
    except Exception as e:
        error_msg = f"Failed to get bulk healthcheck: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e
