# 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 QuickSight API Client

This module provides a clean, modern interface for managing QuickSight resources using the v4 API
with Okta authentication. This replaces legacy QuickSight functions with:
- get_supported_dashboards() -> returns SupportedDashboardsResponse
- create_data_set(data_set) -> returns DataSetResponse
- delete_data_set(data_set) -> returns DataSetResponse
- update_data_sets(data_sets) -> returns DataSetsResponse
- clear_folder_contents(folder) -> returns FolderResponse
- get_spice_report() -> returns SpiceReportResponse
"""

from typing import Any

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

from src.api.authenticated import delete_authenticated, get_authenticated, post_authenticated, put_authenticated
from src.exceptions import APIError

console = Console()


# V4 Pydantic Models - Clean, modern API contract matching backend schema
class Dashboard(BaseModel):
    """QuickSight dashboard model."""

    name: str = Field(..., description="Dashboard identifier")
    display_name: str = Field(..., description="Dashboard display name")
    dashboard_type: str | None = Field(None, description="Dashboard type")
    description: str | None = Field(None, description="Dashboard description")
    supported: bool = Field(default=True, description="Whether dashboard is supported")


class SupportedDashboardsResponse(BaseModel):
    """V4 response model for supported dashboards."""

    dashboards: list[Dashboard] = Field(..., description="List of supported dashboards")
    total_count: int = Field(..., description="Total number of dashboards")


class DataSetDefinition(BaseModel):
    """QuickSight data set definition model."""

    data_set_name: str = Field(..., description="Data set name")
    data_set_id: str | None = Field(None, description="Data set identifier")
    dashboard_name: str | None = Field(None, description="Associated dashboard name")
    params: dict[str, Any] = Field(default_factory=dict, description="Data set parameters")
    schema_definition: dict[str, Any] = Field(default_factory=dict, description="Data set schema")


class DataSetResponse(BaseModel):
    """V4 response model for data set operations."""

    data_set_id: str | None = Field(None, description="Data set identifier")
    data_set_name: str | None = Field(None, description="Data set name")
    operation: str = Field(..., description="Operation performed (create/delete/update)")
    success: bool = Field(..., description="Whether operation was successful")
    message: str | None = Field(None, description="Response message")


class DataSetsResponse(BaseModel):
    """V4 response model for multiple data sets operations."""

    data_sets: list[DataSetResponse] = Field(..., description="List of data set operation results")
    total_processed: int = Field(..., description="Total number of data sets processed")
    successful: int = Field(..., description="Number of successful operations")
    failed: int = Field(..., description="Number of failed operations")


class FolderContents(BaseModel):
    """QuickSight folder contents model."""

    folder_id: str = Field(..., description="Folder identifier")
    folder_name: str | None = Field(None, description="Folder name")
    contents: list[str] = Field(default_factory=list, description="List of items in folder")


class FolderResponse(BaseModel):
    """V4 response model for folder operations."""

    folder_id: str | None = Field(None, description="Folder identifier")
    folder_name: str | None = Field(None, description="Folder name")
    operation: str = Field(..., description="Operation performed")
    items_processed: int = Field(default=0, description="Number of items processed")
    success: bool = Field(..., description="Whether operation was successful")
    message: str | None = Field(None, description="Response message")


class SpiceUsage(BaseModel):
    """SPICE usage information model."""

    total_capacity_mb: float | None = Field(None, description="Total SPICE capacity in MB")
    used_capacity_mb: float | None = Field(None, description="Used SPICE capacity in MB")
    available_capacity_mb: float | None = Field(None, description="Available SPICE capacity in MB")
    utilization_percentage: float | None = Field(None, description="Utilization percentage")


class SpiceReportResponse(BaseModel):
    """V4 response model for SPICE report."""

    usage: SpiceUsage = Field(..., description="SPICE usage information")
    report_date: str | None = Field(None, description="Report generation date")
    success: bool = Field(default=True, description="Whether report was successful")


def get_supported_dashboards(debug: bool = False) -> SupportedDashboardsResponse:
    """
    Get list of supported QuickSight dashboards using v4 API.

    Args:
        debug: Whether to show debug information

    Returns:
        SupportedDashboardsResponse: List of supported dashboards

    Raises:
        APIError: If the API request fails
    """
    if debug:
        console.print("[cyan]DEBUG: Fetching supported dashboards via V4 API[/]")

    try:
        # Make authenticated request to v4 quicksight/supported/dashboards endpoint
        response_data = get_authenticated(endpoint_path="quicksight/supported/dashboards", debug=debug)

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

        # Validate response with Pydantic model
        dashboards_response = SupportedDashboardsResponse(**response_data)

        if debug:
            console.print(
                f"[green]DEBUG: Successfully retrieved {dashboards_response.total_count} supported dashboards[/]"
            )

        return dashboards_response

    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 supported dashboards: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def create_data_set(data_set_definition: dict[str, Any], debug: bool = False) -> DataSetResponse:
    """
    Create a new QuickSight data set using v4 API.

    Args:
        data_set_definition: Data set definition payload
        debug: Whether to show debug information

    Returns:
        DataSetResponse: Result of data set creation

    Raises:
        APIError: If the API request fails
    """
    if not data_set_definition:
        raise ValueError("Data set definition is required")

    if debug:
        console.print("[cyan]DEBUG: Creating QuickSight data set via V4 API[/]")
        console.print(f"[cyan]DEBUG: Data set payload: {data_set_definition}[/]")

    try:
        # Make authenticated request to v4 quicksight/data_set endpoint
        response_data = post_authenticated(
            endpoint_path="quicksight/data_set", json_data=data_set_definition, debug=debug
        )

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

        # Validate response with Pydantic model
        data_set_response = DataSetResponse(**response_data)

        if debug:
            console.print(f"[green]DEBUG: Successfully created data set {data_set_response.data_set_name}[/]")

        return data_set_response

    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 create data set: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def delete_data_set(organization_id: str, dataset_id: str, debug: bool = False) -> dict[str, Any]:
    """
    Delete a QuickSight data set using v4 API.

    Args:
        organization_id: Organization ID
        dataset_id: Data set ID to delete
        debug: Whether to show debug information

    Returns:
        dict: Result of data set deletion

    Raises:
        APIError: If the API request fails
    """
    if not organization_id or not dataset_id:
        raise ValueError("Both organization_id and dataset_id are required")

    if debug:
        console.print(f"[cyan]DEBUG: Deleting QuickSight data set {dataset_id} via V4 API[/]")

    try:
        # Make authenticated request to v4 quicksight/data_set endpoint with query parameters
        params = {"organization_id": organization_id, "dataset_id": dataset_id}

        response_data = delete_authenticated(endpoint_path="quicksight/data_set", params=params, debug=debug)

        if debug:
            console.print(f"[cyan]DEBUG: Raw API response: {response_data}[/]")
            console.print(f"[green]DEBUG: Successfully deleted data set {dataset_id}[/]")

        return response_data

    except APIError:
        # Re-raise API errors as-is
        raise
    except Exception as e:
        error_msg = f"Failed to delete data set {dataset_id}: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def update_data_sets(data_sets_definition: dict[str, Any], debug: bool = False) -> DataSetsResponse:
    """
    Update multiple QuickSight data sets using v4 API.

    Args:
        data_sets_definition: Data sets update payload
        debug: Whether to show debug information

    Returns:
        DataSetsResponse: Result of data sets update

    Raises:
        APIError: If the API request fails
    """
    if not data_sets_definition:
        raise ValueError("Data sets definition is required")

    if debug:
        console.print("[cyan]DEBUG: Updating QuickSight data sets via V4 API[/]")
        console.print(f"[cyan]DEBUG: Data sets payload: {data_sets_definition}[/]")

    try:
        # Make authenticated request to v4 quicksight/data_sets endpoint
        response_data = put_authenticated(
            endpoint_path="quicksight/data_sets", json_data=data_sets_definition, debug=debug
        )

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

        # Validate response with Pydantic model
        data_sets_response = DataSetsResponse(**response_data)

        if debug:
            console.print(f"[green]DEBUG: Successfully updated {data_sets_response.successful} data sets[/]")

        return data_sets_response

    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 update data sets: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def clear_folder_contents(
    organization_id: str, folder_type: str = "customer_data", debug: bool = False
) -> dict[str, Any]:
    """
    Clear contents of a QuickSight folder using v4 API.

    Args:
        organization_id: Organization ID
        folder_type: Folder type to clear (default: customer_data)
        debug: Whether to show debug information

    Returns:
        dict: Result of folder clear operation

    Raises:
        APIError: If the API request fails
    """
    if not organization_id:
        raise ValueError("Organization ID is required")

    if debug:
        console.print(f"[cyan]DEBUG: Clearing QuickSight folder contents for org {organization_id} via V4 API[/]")

    try:
        # Make authenticated request to v4 quicksight/folder/contents endpoint with query parameters
        params = {"organization_id": organization_id, "folder_type": folder_type}

        response_data = delete_authenticated(endpoint_path="quicksight/folder/contents", params=params, debug=debug)

        if debug:
            console.print(f"[cyan]DEBUG: Raw API response: {response_data}[/]")
            console.print(f"[green]DEBUG: Successfully cleared folder contents for org {organization_id}[/]")

        return response_data

    except APIError:
        # Re-raise API errors as-is
        raise
    except Exception as e:
        error_msg = f"Failed to clear folder contents: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e


def get_spice_report(organization_id: str, debug: bool = False) -> dict[str, Any]:
    """
    Get SPICE capacity and usage report using v4 API.

    Args:
        organization_id: Organization ID
        debug: Whether to show debug information

    Returns:
        dict: SPICE usage information

    Raises:
        APIError: If the API request fails
    """
    if not organization_id:
        raise ValueError("Organization ID is required")

    if debug:
        console.print(f"[cyan]DEBUG: Fetching SPICE report for org {organization_id} via V4 API[/]")

    try:
        # Make authenticated request to v4 quicksight/spice_report endpoint with query parameters
        params = {"organization_id": organization_id}

        response_data = get_authenticated(endpoint_path="quicksight/spice_report", params=params, debug=debug)

        if debug:
            console.print(f"[cyan]DEBUG: Raw API response: {response_data}[/]")
            console.print(f"[green]DEBUG: Successfully retrieved SPICE report for org {organization_id}[/]")

        return response_data

    except APIError:
        # Re-raise API errors as-is
        raise
    except Exception as e:
        error_msg = f"Failed to get SPICE report for org {organization_id}: {str(e)}"
        if debug:
            console.print(f"[red]DEBUG: Unexpected error: {error_msg}[/]")
        raise APIError(error_msg) from e
