# Copyright (c) 2025 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
#

"""
QuickSight command group for CloudZero Operations CLI

This module provides commands for managing QuickSight dashboards and datasets
using the V4 API endpoints.
"""

import csv
import json
import sys
from collections import defaultdict
from datetime import datetime

from rich.console import Console
from rich.table import Table
from tabulate import tabulate

from src.api.v4_organizations import get_organizations
from src.api.v4_quicksight import (
    clear_folder_contents,
    create_data_set,
    delete_data_set,
    get_spice_report,
    get_supported_dashboards,
    update_data_sets,
)
from src.exceptions import APIError

# Initialize Rich console
console = Console()

# Preserve whitespace in tabulate output
tabulate.PRESERVE_WHITESPACE = True


def list_dashboards(arguments):
    """List supported QuickSight dashboards for organizations."""
    org_records = get_organizations()
    cz_org_id = arguments.get("<ORG-ID>")

    if cz_org_id:
        # Filter to single organization
        if cz_org_id in org_records:
            org_records = {cz_org_id: org_records[cz_org_id]}
        else:
            # Try to find by name
            for org_id, org_details in org_records.items():
                if org_details.organization_name.lower() == cz_org_id.lower():
                    org_records = {org_id: org_details}
                    cz_org_id = org_id
                    break
            else:
                print(f"Organization '{cz_org_id}' not found")
                sys.exit(1)
        print(" - Fetching supported QuickSight dashboards for organization", end="")
    else:
        print(" - Fetching supported QuickSight dashboards for all organizations", end="")

    headers = ["Name", "Display Name".ljust(45), "Supported".ljust(15)]
    report_data = defaultdict(list)

    try:
        # Get supported dashboards from QuickSight V4 API
        dashboards_response = get_supported_dashboards(debug=arguments.get("--debug", False))

        # Process each organization
        for org_id, org_details in org_records.items():
            org_name = org_details.organization_name
            print(".", end="", flush=True)

            # Add each supported dashboard for this organization
            for dashboard in dashboards_response.dashboards:
                report_data[f"{org_name} ({org_id})"].append(
                    {
                        "cz_organization_id": org_id,
                        "cz_organization_name": org_name,
                        "dashboard_name": dashboard.name,
                        "display_name": dashboard.display_name,
                        "supported": "Yes" if dashboard.supported else "No",
                        "description": dashboard.description or "No description available",
                    }
                )

    except APIError as e:
        print(f"\n\nError fetching QuickSight dashboards: {e}")
        sys.exit(1)
    except Exception as e:
        print(f"\n\nUnexpected error: {e}")
        sys.exit(1)

    print(f"loaded {len([item for sublist in report_data.values() for item in sublist])} supported dashboards")

    # Handle output to file if requested
    if arguments.get("--output") or arguments.get("-o"):
        csv_file = arguments.get("--output") or arguments.get("-o")
        print(f" - Exporting data to {csv_file}")
        flattened_report_data = [item for sublist in report_data.values() for item in sublist]
        try:
            with open(csv_file, "w") as csvfile:
                # Ensure no rich text formatting in CSV export
                clean_data = []
                for item in flattened_report_data:
                    clean_item = {}
                    for key, value in item.items():
                        # Convert any formatted values to plain text
                        if isinstance(value, str):
                            # Remove any Rich formatting markup
                            clean_value = value.replace("[", "").replace("]", "")
                            clean_item[key] = clean_value
                        else:
                            clean_item[key] = value
                    clean_data.append(clean_item)

                if clean_data:  # Only write if we have data
                    writer = csv.DictWriter(csvfile, fieldnames=clean_data[0].keys(), dialect="excel", quoting=csv.QUOTE_ALL)
                    writer.writeheader()
                    for data in clean_data:
                        writer.writerow(data)
        except OSError as error:
            print(f"I/O error ({error})")
            sys.exit(-1)
        print(f" - Export complete, {len(flattened_report_data)} rows written")
    else:
        # Display to console
        for org_title, dashboards in report_data.items():
            dashboards_table = []
            console.print(f"\n+ [bold white]{org_title} [/]".ljust(150, "-") + "+")
            for dashboard in dashboards:
                dashboards_table.append([dashboard["dashboard_name"], dashboard["display_name"], dashboard["supported"]])
            print(
                tabulate(
                    dashboards_table,
                    headers,
                    tablefmt="orgtbl",
                    numalign="left",
                    colalign=("left", "left", "center"),
                    maxcolwidths=[36, 45, 15],
                ),
                end="",
            )
        print(f"\n+{'-' * 148}+")


def create_dataset(arguments):
    """Create a new QuickSight dataset for an organization."""
    cz_org_id = arguments.get("<ORG-ID>")
    dashboard_name = arguments.get("--dashboard")
    params_str = arguments.get("--params")

    if not cz_org_id or not dashboard_name:
        print("Error: Organization ID and dashboard name are required")
        sys.exit(1)

    # Parse params if provided
    params = {}
    if params_str:
        try:
            # Handle @file syntax
            if params_str.startswith("@"):
                file_path = params_str[1:]
                with open(file_path) as f:
                    params = json.load(f)
            # Handle stdin
            elif params_str == "-":
                params = json.load(sys.stdin)
            # Handle inline JSON
            else:
                params = json.loads(params_str)
        except (json.JSONDecodeError, FileNotFoundError) as e:
            print(f"Error parsing params: {e}")
            sys.exit(1)

    # Prepare the payload
    payload = {"organization_id": cz_org_id, "dashboard_name": dashboard_name, "dataset_params": params}

    try:
        result = create_data_set(payload, debug=arguments.get("--debug", False))
        print(f"✅ Dataset created successfully for {dashboard_name} dashboard")
        if arguments.get("--debug"):
            print(json.dumps(result, indent=2))
    except APIError as e:
        print(f"❌ Error creating dataset: {e}")
        sys.exit(1)


def delete_dataset(arguments):
    """Delete a QuickSight dataset."""
    cz_org_id = arguments.get("<ORG-ID>")
    dataset_id = arguments.get("--dataset-id")

    if not cz_org_id or not dataset_id:
        print("Error: Organization ID and dataset ID are required")
        sys.exit(1)

    try:
        result = delete_data_set(cz_org_id, dataset_id, debug=arguments.get("--debug", False))
        print(f"✅ Dataset {dataset_id} deleted successfully")
        if arguments.get("--debug"):
            print(json.dumps(result, indent=2))
    except APIError as e:
        print(f"❌ Error deleting dataset: {e}")
        sys.exit(1)


def clear_folder(arguments):
    """Clear QuickSight folder contents for an organization."""
    cz_org_id = arguments.get("<ORG-ID>")
    folder_type = arguments.get("--folder-type", "customer_data")

    if not cz_org_id:
        print("Error: Organization ID is required")
        sys.exit(1)

    # Ask for confirmation
    org_name = "Unknown"
    try:
        orgs = get_organizations()
        org_details = orgs.get(cz_org_id)
        if org_details:
            org_name = org_details.organization_name if hasattr(org_details, "organization_name") else org_details.get("organization_name", cz_org_id)
    except Exception:
        pass

    if not arguments.get("--force"):
        response = input(f"Are you sure you want to clear {folder_type} folder for {org_name} ({cz_org_id})? (y/n): ")
        if response.lower() != "y":
            print("Operation cancelled")
            return

    try:
        result = clear_folder_contents(cz_org_id, folder_type, debug=arguments.get("--debug", False))
        print(f"✅ Folder {folder_type} cleared successfully for organization {org_name}")
        if arguments.get("--debug"):
            print(json.dumps(result, indent=2))
    except APIError as e:
        print(f"❌ Error clearing folder: {e}")
        sys.exit(1)


def spice_report(arguments):
    """Get SPICE usage report for an organization."""
    cz_org_id = arguments.get("<ORG-ID>")

    if not cz_org_id:
        print("Error: Organization ID is required")
        sys.exit(1)

    try:
        result = get_spice_report(cz_org_id, debug=arguments.get("--debug", False))

        # Display the report in a nice table format
        console.print("\n[bold cyan]QuickSight SPICE Usage Report[/]")
        console.print(f"Organization: {cz_org_id}")
        console.print(f"Report Date: {datetime.utcnow().isoformat()}Z\n")

        # Create usage summary table
        usage_table = Table(title="SPICE Capacity Usage")
        usage_table.add_column("Metric", style="cyan", no_wrap=True)
        usage_table.add_column("Value", style="green")

        if "total_capacity_gb" in result:
            usage_table.add_row("Total Capacity", f"{result['total_capacity_gb']:.2f} GB")
            usage_table.add_row("Used Capacity", f"{result.get('used_capacity_gb', 0):.2f} GB")
            usage_table.add_row("Available Capacity", f"{result.get('available_capacity_gb', 0):.2f} GB")
            usage_table.add_row("Usage Percentage", f"{result.get('usage_percentage', 0):.1f}%")

        console.print(usage_table)

        # Show datasets if available
        if "datasets" in result and result["datasets"]:
            console.print("\n[bold]Datasets:[/]")
            dataset_table = Table()
            dataset_table.add_column("Dataset ID", style="cyan")
            dataset_table.add_column("Name", style="green")
            dataset_table.add_column("Size (GB)", style="yellow")
            dataset_table.add_column("Last Refresh", style="magenta")

            for ds in result["datasets"]:
                dataset_table.add_row(
                    ds.get("dataset_id", "N/A"), ds.get("name", "N/A"), f"{ds.get('size_gb', 0):.2f}", ds.get("last_refresh", "N/A")
                )

            console.print(dataset_table)

        # Save to file if requested
        if arguments.get("--output") or arguments.get("-o"):
            output_file = arguments.get("--output") or arguments.get("-o")
            with open(output_file, "w") as f:
                json.dump(result, f, indent=2)
            print(f"\n✅ Report saved to {output_file}")

    except APIError as e:
        print(f"❌ Error getting SPICE report: {e}")
        sys.exit(1)


def update_datasets(arguments):
    """Update multiple QuickSight datasets."""
    cz_org_id = arguments.get("<ORG-ID>")
    dataset_ids_str = arguments.get("--dataset-ids")

    if not cz_org_id or not dataset_ids_str:
        print("Error: Organization ID and dataset IDs are required")
        sys.exit(1)

    # Parse dataset IDs
    dataset_ids = []
    try:
        # Handle @file syntax
        if dataset_ids_str.startswith("@"):
            file_path = dataset_ids_str[1:]
            with open(file_path) as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith("#"):
                        dataset_ids.append(line)
        # Handle comma-separated
        else:
            dataset_ids = [id.strip() for id in dataset_ids_str.split(",") if id.strip()]
    except FileNotFoundError as e:
        print(f"Error reading dataset IDs file: {e}")
        sys.exit(1)

    if not dataset_ids:
        print("Error: No valid dataset IDs provided")
        sys.exit(1)

    # Prepare the payload
    payload = {"organization_id": cz_org_id, "dataset_ids": dataset_ids}

    try:
        result = update_data_sets(payload, debug=arguments.get("--debug", False))

        # Display results
        if "datasets_updated" in result:
            successful = [ds for ds in result["datasets_updated"] if ds.get("status") == "updated"]
            failed = [ds for ds in result["datasets_updated"] if ds.get("status") != "updated"]

            print(f"\n✅ Successfully updated {len(successful)} dataset(s)")
            if failed:
                print(f"⚠️  Failed to update {len(failed)} dataset(s)")
                for ds in failed:
                    print(f"  - {ds.get('dataset_id', 'unknown')}: {ds.get('error', 'unknown error')}")
        else:
            print(f"✅ Datasets update initiated for {len(dataset_ids)} dataset(s)")

        if arguments.get("--debug"):
            print("\nFull response:")
            print(json.dumps(result, indent=2))

    except APIError as e:
        print(f"❌ Error updating datasets: {e}")
        sys.exit(1)


def handle_command(arguments):
    """Main entry point for QuickSight commands."""
    if arguments.get("list"):
        list_dashboards(arguments)
    elif arguments.get("create-dataset"):
        create_dataset(arguments)
    elif arguments.get("delete-dataset"):
        delete_dataset(arguments)
    elif arguments.get("clear-folder"):
        clear_folder(arguments)
    elif arguments.get("spice-report"):
        spice_report(arguments)
    elif arguments.get("update-datasets"):
        update_datasets(arguments)
    else:
        print("Unknown QuickSight command")
        sys.exit(1)
