from typing import Union, Dict, List
from bson import ObjectId

def convert_objectid_ohlc(data: Union[Dict, List]) -> Union[Dict, List]:
    """Convert MongoDB ObjectId to string in nested structures."""
    if isinstance(data, dict):
        return {k: str(v) if isinstance(v, ObjectId) else convert_objectid_ohlc(v)
                for k, v in data.items()}
    elif isinstance(data, list):
        return [convert_objectid_ohlc(item) for item in data]
    return data

def process_summary_calculations(report_type, total_prices):
    """Helper function to process summary calculations"""
    summary_total = {"summary_total": []}
    sorted_dates = sorted(total_prices.keys())

    # Total entry
    total_entry = {
        "type": report_type,
        "symbol": "TOTAL",
        "qty": "",
        "avg_price": "",
        **{date: total_prices[date] for date in sorted_dates}
    }
    summary_total["summary_total"].append(total_entry)

    # Total Change entry
    if sorted_dates:
        first_total = total_prices[sorted_dates[0]]
        change_entry = {
            "type": report_type,
            "symbol": f"% TOTAL CHANGE in {report_type}",
            "qty": "",
            "avg_price": "",
            **{
                date: "-" if first_total == 0 else
                round(((total_prices[date] - first_total) / first_total * 100), 2)
                for date in sorted_dates
            }
        }
        summary_total["summary_total"].append(change_entry)

    # Day Change entries
    day_changes = calculate_day_changes(report_type, sorted_dates, total_prices)
    summary_total["summary_total"].extend(day_changes)

    return summary_total

def calculate_day_changes(report_type, sorted_dates, total_prices):
    """Helper function to calculate day changes"""
    day_changes = {}
    day_change_entries = []

    # Day Change
    day_change_entry = {
        "type": report_type,
        "symbol": f"DAY CHANGE in {report_type}",
        "qty": "",
        "avg_price": "",
    }

    for i, date in enumerate(sorted_dates):
        if i == 0:
            day_changes[date] = "-"
        else:
            prev_date = sorted_dates[i-1]
            day_changes[date] = round(total_prices[date] - total_prices[prev_date], 2)
        day_change_entry[date] = day_changes[date]

    day_change_entries.append(day_change_entry)

    # Day Change Percentage
    day_change_percent_entry = {
        "type": report_type,
        "symbol": f"DAY CHANGE % in {report_type}",
        "qty": "",
        "avg_price": "",
        **{
            date: "-" if i == 0 or total_prices[sorted_dates[i-1]] == 0 else
            round((day_changes[date] / total_prices[sorted_dates[i-1]] * 100), 2)
            for i, date in enumerate(sorted_dates)
        }
    }
    day_change_entries.append(day_change_percent_entry)

    return day_change_entries

def process_metrics(results_by_type, sorted_dates):
    """Helper function to process metrics for summary report"""
    metrics = {
        "high_minus_open": {"symbol": "High - Open"},
        "open_minus_low": {"symbol": "Open - Low"},
        "high_minus_low": {"symbol": "High - Low"},
        "open_minus_close": {"symbol": "Open - Close"},
        "high_minus_open_pr": {"symbol": "High - Open %"},
        "open_minus_low_pr": {"symbol": "Open - Low %"},
        "high_minus_low_pr": {"symbol": "High - Low %"},
        "open_minus_close_pr": {"symbol": "Open - Close %"}
    }

    for metric, result in metrics.items():
        for date in sorted_dates:
            try:
                calculate_metric_value(metric, date, result, results_by_type)
            except KeyError:
                continue

    results_by_type["summary_report"].update(metrics)

def calculate_metric_value(metric, date, result, results_by_type):
    """
    Helper function to calculate various metric values for the summary report

    Args:
        metric (str): The type of metric to calculate
        date (str): The date for which to calculate the metric
        result (dict): Dictionary to store the calculated result
        results_by_type (dict): The full results dictionary containing all report types
    """
    # Get the required values based on metric type
    if metric.endswith("_pr"):
        # For percentage calculations
        base_metric = metric.replace("_pr", "")
        values = get_metric_values(base_metric, date, results_by_type)
        if values[1] == 0:  # Avoid division by zero
            result[date] = "-"
        else:
            result[date] = round((values[0] - values[1]) / values[1] * 100, 2)
    else:
        # For absolute value calculations
        values = get_metric_values(metric, date, results_by_type)
        result[date] = round(values[0] - values[1], 2)

def get_metric_values(metric, date, results_by_type):
    """
    Helper function to get the appropriate values for metric calculation

    Args:
        metric (str): The type of metric
        date (str): The date for which to get values
        results_by_type (dict): The full results dictionary containing all report types

    Returns:
        tuple: A pair of values needed for the metric calculation
    """
    if metric == "high_minus_open":
        return (
            results_by_type["summary_report"]["high"][date],
            results_by_type["summary_report"]["open"][date]
        )
    elif metric == "open_minus_low":
        return (
            results_by_type["summary_report"]["open"][date],
            results_by_type["summary_report"]["low"][date]
        )
    elif metric == "high_minus_low":
        return (
            results_by_type["summary_report"]["high"][date],
            results_by_type["summary_report"]["low"][date]
        )
    elif metric == "open_minus_close":
        return (
            results_by_type["summary_report"]["open"][date],
            results_by_type["summary_report"]["close"][date]
        )
    else:
        raise ValueError(f"Unknown metric type: {metric}")












#from typing import Union, Dict, List
#from bson import ObjectId
#
#def convert_objectid_ohlc(data: Union[Dict, List]) -> Union[Dict, List]:
#    """Convert MongoDB ObjectId to string in nested structures."""
#    if isinstance(data, dict):
#        return {k: str(v) if isinstance(v, ObjectId) else convert_objectid_ohlc(v)
#                for k, v in data.items()}
#    elif isinstance(data, list):
#        return [convert_objectid_ohlc(item) for item in data]
#    return data
