#!/usr/bin/env python3
# Copyright (c) 2020 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
#
import json
import math
import sys
from datetime import timedelta
from typing import Any

from rich.console import Console
from toolz.dicttoolz import keymap

from src.utils.console import eprint, print_error
from src.utils.url_builder import resolve_link_mechanics

# Initialize Rich console
console = Console()


def _get_filters_for_classic_anomaly(row: dict[str, Any]) -> dict[str, Any]:
    """Extract filters from a classic anomaly row.

    Args:
        row: Dictionary containing anomaly data with keys like product_name, account_id, etc.

    Returns:
        Dictionary of filters for URL construction
    """
    filters = {}

    # Safely get values from dict
    product_name = row.get("product_name")
    account_id = row.get("account_id")
    product_family = row.get("product_family")
    feature = row.get("feature")

    # Add filters only if values exist and are not None/"None"
    if _not_none(product_name):
        filters["services"] = product_name
    if _not_none(account_id):
        filters["accounts"] = account_id
    if _not_none(product_family):
        filters["product_family"] = product_family
    if _not_none(feature):
        filters["feature"] = feature

    return filters


def _not_none(s: Any | None) -> bool:
    """Check if a value is not None or the string 'None'."""
    return bool(s and (s != "None"))


def _get_filters_for_view_anomaly(row: dict[str, Any]) -> dict[str, Any]:
    """Extract filters from a view anomaly row.

    Args:
        row: Dictionary containing view anomaly data with view_filter_json, dimension, and element keys

    Returns:
        Dictionary of filters for URL construction
    """
    view_filter_json = row.get("view_filter_json")

    try:
        view_filter = json.loads(view_filter_json) if view_filter_json else {}
    except (TypeError, json.JSONDecodeError) as e:
        print_error("Failed to parse the view filter for an anomaly row.", error_type="general")
        if view_filter_json is None:
            console.print("ERROR: View Filter for row cannot be None\n", style="red bold")
        else:
            console.print(f"ERROR: View Filter for row is not valid JSON: {e}\n", style="red bold")
        console.print(
            "- The bad row is -----------------------------------------------------------------------------------\n",
            style="yellow bold",
        )
        eprint(row)
        sys.exit(-1)

    # Safely get dimension and element from dict
    dimension = row.get("dimension")
    element = row.get("element")

    if dimension and element:
        filters = {**view_filter, dimension: element}
    else:
        filters = view_filter
        if not dimension:
            console.print("WARNING: Missing 'dimension' key in row", style="yellow")
        if not element:
            console.print("WARNING: Missing 'element' key in row", style="yellow")

    return _fix_filters(filters)


def _fix_filters(filters: dict[str, Any]) -> dict[str, Any]:
    """Fix filter key names to match expected API format.

    Args:
        filters: Dictionary with potentially incorrect key names

    Returns:
        Dictionary with corrected key names
    """
    fix = {"account_id": "accounts", "product_name": "services"}
    return keymap(
        lambda x: fix.get(x) or x,
        filters,
    )


def _is_view_anomaly(row: dict[str, Any]) -> bool:
    """Check if a row represents a view anomaly.

    Args:
        row: Dictionary containing anomaly data

    Returns:
        True if this is a view anomaly, False otherwise
    """
    return "view_id" in row and _not_none(row.get("view_id"))


def get_url_for_row(row: dict[str, Any]) -> str:
    """Generate URL for anomaly row.

    Args:
        row: Dictionary containing anomaly data with start_time and end_time keys

    Returns:
        URL string for viewing the anomaly in CloudZero explorer
    """
    # Get time values from dict
    start_time = row.get("start_time")
    end_time = row.get("end_time")

    if not start_time or not end_time:
        console.print("ERROR: Missing start_time or end_time in row data", style="red bold")
        console.print(f"Row keys present: {list(row.keys())}", style="yellow")
        sys.exit(-1)

    # Calculate time difference and round up to the next day
    time_diff = end_time - start_time
    days_float = time_diff.total_seconds() / 86400  # Convert to days
    days_ceil = math.ceil(days_float) if days_float > 0 else 1  # Ensure at least 1 day
    delta = timedelta(days=days_ceil)

    dashboard_start_time = start_time - delta
    dashboard_end_time = end_time + delta

    filters = _get_filters_for_view_anomaly(row) if _is_view_anomaly(row) else _get_filters_for_classic_anomaly(row)

    return resolve_link_mechanics(
        partition="resources",
        date_selection={
            "date_range": "Custom",
            "start_date": dashboard_start_time.replace(tzinfo=None),
            "end_date": dashboard_end_time.replace(tzinfo=None),
        },
        filters=filters,
        granularity="hourly",
        show_right_flyout="events",
    )
