from copy import deepcopy
from importlib.resources import files
from typing import Any, Dict, List

from .. import RELAIData
from ...utils import format_title


class BarPlot(RELAIData):
    """Data model for a bar plot component.

    Args:
        title (str): The main title of the chart.
        x_axis_label (str): The label for the chart's X-axis.
        y_axis_label (str): The label for the chart's Y-axis.
        data_key (str): The key in each data object that represents the primary label for the bar.
        data (List[Dict[str, Any]]): An array of data objects to be plotted. Each object must contain at least
            the data_key and one numeric value.
        column_span (int, optional): Number of columns the component should span. Defaults to 12.

    Examples:
        >>> # Create a simple bar plot showing performance by benchmark
        >>> data = [
        >>>     { "benchmark": "Summarization", "score": 0.6203 },
                >>>     { "benchmark": "Q&A Standard", "score": 0.5452 },
                >>>     { "benchmark": "Q&A Reasoning", "score": 0.7738 },
        >>> ]
        >>> bar_plot = BarPlot(
        >>>     title="Performance comparison across all benchmarks",
        >>>     x_axis_label="Benchmark",
        >>>     y_axis_label="Score",
        >>>     data_key="benchmark",
        >>>     data=data
        >>> )
    """

    schema_file: str = files("relai_visualization").joinpath("schema/components/bar-plot.schema.json")

    def __init__(
        self,
        title: str,
        x_axis_label: str,
        y_axis_label: str,
        data_key: str,
        data: List[Dict[str, Any]],
        column_span: int = 12,
    ) -> None:
        # Make a deep copy of the data to avoid modifying the original
        data = deepcopy(data)

        super().__init__(
            componentName="plot",
            type="bar",
            title=format_title(title),
            xAxisLabel=x_axis_label,
            yAxisLabel=y_axis_label,
            dataKey=data_key,
            data=data,
            columnSpan=column_span,
        )

    def custom_validation(self) -> None:
        """Custom validation for the bar plot data.

        Validates that:
        1. Data is not empty
        2. All data points contain the specified data_key
        3. Each data point has at least one numeric value
        """
        # Check that data is not empty
        if not self.data["data"]:
            raise ValueError("Data cannot be empty")

        data_key = self.data["dataKey"]

        for item in self.data["data"]:
            # Check that the item contains the data_key
            if data_key not in item:
                raise ValueError(f"All data points must contain the key '{data_key}'")

            # Ensure each data point has at least one other property (numeric value)
            if len(item) < 2:
                raise ValueError("Each data point must have at least one numeric value in addition to the data key")

            # Check that there's at least one numeric value
            has_numeric = False
            for key, value in item.items():
                if key != data_key and isinstance(value, (int, float)):
                    has_numeric = True
                    break

            if not has_numeric:
                raise ValueError(f"Data point '{item}' does not contain any numeric values")
