"""Mini-chart engine for battle card embeddings."""
import argparse
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.path import Path as MPLPath
# Python 3.14 matplotlib patch (required)
_orig = MPLPath.__deepcopy__
def _safe_deepcopy(self, memo):
    if id(self) in memo:
        return memo[id(self)]
    memo[id(self)] = self
    return self
MPLPath.__deepcopy__ = _safe_deepcopy

from pathlib import Path

from src.utils.styling import (
    get_theme,
    BUBBLE_ZONE,
    AI_SPEND,
    REVENUE,
    WARNING_ZONE,
    GRAY_DARK,
    GRAY_MEDIUM,
    WHITE,
)

MINI_FIGURE_SIZE = (5, 3)
MINI_DPI = 300
MIN_LABEL_FONT_SIZE = 9
MIN_ANNOTATION_FONT_SIZE = 11
MIN_TITLE_FONT_SIZE = 13


class MiniChartEngine:
    """Engine for generating compact, themed mini-charts for battle cards."""

    def _init_figure(self, title: str):
        """Create a themed figure and axes."""
        plt.rcParams.update(get_theme())
        fig, ax = plt.subplots(figsize=MINI_FIGURE_SIZE)
        fig.set_facecolor(WHITE)
        ax.set_facecolor(WHITE)
        ax.spines["top"].set_visible(False)
        ax.spines["right"].set_visible(False)
        ax.spines["left"].set_color("#cccccc")
        ax.spines["bottom"].set_color("#cccccc")
        ax.set_title(title, fontsize=MIN_TITLE_FONT_SIZE, fontweight="bold", pad=8)
        return fig, ax

    def _save(self, fig, save_path: str) -> str:
        """Save figure with tight layout."""
        Path(save_path).parent.mkdir(parents=True, exist_ok=True)
        fig.savefig(save_path, dpi=MINI_DPI, bbox_inches="tight", pad_inches=0.15)
        plt.close(fig)
        return save_path

    def generate_line_trend(
        self,
        years,
        values,
        title,
        save_path,
        highlight_year=None,
        highlight_value=None,
        color=GRAY_DARK,
        secondary_color=None,
    ):
        """Single line chart showing trend over time."""
        fig, ax = self._init_figure(title)

        ax.plot(years, values, color=color, linewidth=2, marker="o", markersize=5)

        # Highlight year
        if highlight_year is not None:
            idx = years.index(highlight_year) if highlight_year in years else len(years) - 1
            ax.axvline(
                x=highlight_year,
                color=BUBBLE_ZONE,
                linestyle="--",
                linewidth=1,
                alpha=0.7,
            )
            if highlight_value is not None:
                ax.annotate(
                    str(highlight_value),
                    xy=(highlight_year, values[idx]),
                    xytext=(5, 10),
                    textcoords="offset points",
                    fontsize=MIN_ANNOTATION_FONT_SIZE,
                    fontweight="bold",
                    color=BUBBLE_ZONE,
                )

        ax.tick_params(axis="both", labelsize=MIN_LABEL_FONT_SIZE)
        ax.grid(True, axis="y", alpha=0.4)
        plt.tight_layout()
        return self._save(fig, save_path)

    def generate_horizontal_bar(
        self,
        categories,
        values,
        title,
        save_path,
        colors=None,
        value_labels=None,
        max_value=None,
    ):
        """Horizontal bar chart for comparing categories."""
        fig, ax = self._init_figure(title)

        if colors is None:
            colors = [AI_SPEND] * len(categories)

        y_pos = range(len(categories))
        bars = ax.barh(
            y_pos, values, color=colors[: len(categories)], height=0.55
        )

        # Value labels on bars
        if value_labels is not None:
            for bar, label in zip(bars, value_labels):
                ax.text(
                    bar.get_width() + max(values) * 0.01,
                    bar.get_y() + bar.get_height() / 2,
                    str(label),
                    va="center",
                    fontsize=MIN_LABEL_FONT_SIZE,
                    color=GRAY_DARK,
                )

        ax.set_yticks(list(y_pos))
        ax.set_yticklabels(categories, fontsize=MIN_LABEL_FONT_SIZE)
        ax.tick_params(axis="x", labelsize=MIN_LABEL_FONT_SIZE)

        if max_value is not None:
            ax.set_xlim(0, max_value * 1.15)

        ax.grid(True, axis="x", alpha=0.3)
        plt.tight_layout()
        return self._save(fig, save_path)

    def generate_utilization_bar(
        self,
        label,
        percentage,
        title,
        save_path,
        context_text=None,
    ):
        """Single horizontal bar showing utilization rate."""
        fig, ax = self._init_figure(title)

        # Color coding based on percentage
        if percentage > 50:
            bar_color = REVENUE  # green
        elif percentage >= 20:
            bar_color = WARNING_ZONE  # orange
        else:
            bar_color = BUBBLE_ZONE  # red

        # Background track
        ax.barh(
            0,
            100,
            height=0.6,
            color="#ecf0f1",
            edgecolor="#cccccc",
            linewidth=0.5,
        )

        # Filled utilization bar
        bar = ax.barh(0, percentage, height=0.6, color=bar_color)

        # Large percentage annotation on the bar
        ax.text(
            percentage / 2,
            0,
            f"{percentage:.0f}%",
            ha="center",
            va="center",
            fontsize=MIN_ANNOTATION_FONT_SIZE + 3,
            fontweight="bold",
            color=WHITE if percentage > 10 else GRAY_DARK,
        )

        # Label
        ax.set_yticks([])
        ax.set_xlim(0, 100)
        ax.text(
            0.02,
            -0.25,
            str(label),
            transform=ax.transData,
            fontsize=MIN_LABEL_FONT_SIZE,
            color=GRAY_DARK,
        )

        # Context text below the bar
        if context_text is not None:
            ax.text(
                50,
                -0.55,
                context_text,
                ha="center",
                fontsize=MIN_LABEL_FONT_SIZE,
                color=GRAY_MEDIUM,
                style="italic",
            )

        ax.set_ylim(-0.9, 0.5)
        ax.axis("off")
        plt.tight_layout()
        return self._save(fig, save_path)

    def generate_comparison_bar(
        self,
        categories,
        values_left,
        values_right,
        title,
        save_path,
        label_left=None,
        label_right=None,
        colors=None,
    ):
        """Side-by-side grouped bar chart for comparisons."""
        fig, ax = self._init_figure(title)

        if colors is None:
            color_left = AI_SPEND
            color_right = GRAY_MEDIUM
        elif len(colors) >= 2:
            color_left = colors[0]
            color_right = colors[1]
        else:
            color_left = colors[0] if len(colors) == 1 else AI_SPEND
            color_right = GRAY_MEDIUM

        x = list(range(len(categories)))
        width = 0.35

        bars_left = ax.bar(
            [p - width / 2 for p in x],
            values_left,
            width,
            label=label_left or "Left",
            color=color_left,
        )
        bars_right = ax.bar(
            [p + width / 2 for p in x],
            values_right,
            width,
            label=label_right or "Right",
            color=color_right,
        )

        ax.set_xticks(x)
        ax.set_xticklabels(categories, fontsize=MIN_LABEL_FONT_SIZE)
        ax.tick_params(axis="y", labelsize=MIN_LABEL_FONT_SIZE)
        ax.legend(
            loc="upper center",
            bbox_to_anchor=(0.5, -0.12),
            ncol=2,
            fontsize=MIN_LABEL_FONT_SIZE,
        )
        ax.grid(True, axis="y", alpha=0.3)
        plt.tight_layout()
        return self._save(fig, save_path)


# ---------------------------------------------------------------------------
# Standalone convenience functions (for use by card workers)
# ---------------------------------------------------------------------------

def create_cape_chart(years, values, save_path):
    """Create historical CAPE trend with current value highlighted."""
    engine = MiniChartEngine()
    engine.generate_line_trend(
        years=years,
        values=values,
        title="CAPE Ratio Trend",
        save_path=save_path,
        highlight_year=years[-1],
        highlight_value=values[-1],
        color=GRAY_DARK,
    )


def create_capex_chart(companies, values, save_path):
    """Create hyperscaler capex comparison bar chart."""
    engine = MiniChartEngine()
    colors_list = [AI_SPEND, WARNING_ZONE, REVENUE, GRAY_MEDIUM, BUBBLE_ZONE]
    engine.generate_horizontal_bar(
        categories=companies,
        values=values,
        title="Hyperscaler AI Capex",
        save_path=save_path,
        colors=colors_list[: len(companies)],
        value_labels=[f"${v}B" for v in values],
        max_value=max(values) * 1.3,
    )


def create_utilization_chart(percentage, context_text, save_path):
    """Create GPU utilization gauge chart."""
    engine = MiniChartEngine()
    engine.generate_utilization_bar(
        label="GPU Utilization",
        percentage=percentage,
        title="Current GPU Utilization",
        save_path=save_path,
        context_text=context_text,
    )


def create_vulnerability_chart(ai_rate, non_ai_rate, save_path):
    """Create AI vs non-AI code vulnerability comparison."""
    engine = MiniChartEngine()
    engine.generate_comparison_bar(
        categories=["Code Vulnerability Rate"],
        values_left=[ai_rate],
        values_right=[non_ai_rate],
        title="AI vs Non-AI Code Vulnerability",
        save_path=save_path,
        label_left="AI-Generated Code",
        label_right="Human-Generated Code",
        colors=[BUBBLE_ZONE, GRAY_MEDIUM],
    )


# ---------------------------------------------------------------------------
# CLI test entry point
# ---------------------------------------------------------------------------

def _run_tests() -> None:
    """Generate 4 test charts demonstrating each chart type."""
    base_dir = Path("output/battlecards/charts")
    engine = MiniChartEngine()
    base_dir.mkdir(parents=True, exist_ok=True)

    # Test 1: Line trend — CAPE-like trend with 2026 highlighted
    years = [2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026]
    cape_values = [18.2, 28.5, 31.1, 25.3, 22.7, 33.8, 37.2, 41.5, 44.8]
    path1 = engine.generate_line_trend(
        years=years,
        values=cape_values,
        title="S&P 500 CAPE Ratio Trend",
        save_path=str(base_dir / "test_line_trend.png"),
        highlight_year=2026,
        highlight_value="44.8x",
        color=GRAY_DARK,
    )
    print(f"  [1/4] Line trend: {path1}")

    # Test 2: Horizontal bar — Hyperscaler capex comparison
    companies = ["Microsoft", "Amazon", "Google", "Meta"]
    capex_values = [234, 118, 90, 72]
    capex_colors = ["#00a4ef", "#ff9900", "#4285f4", "#1877f2"]
    path2 = engine.generate_horizontal_bar(
        categories=companies,
        values=capex_values,
        title="2025 AI Infrastructure Capex ($B)",
        save_path=str(base_dir / "test_horizontal_bar.png"),
        colors=capex_colors,
        value_labels=[f"${v}B" for v in capex_values],
        max_value=280,
    )
    print(f"  [2/4] Horizontal bar: {path2}")

    # Test 3: Utilization bar — GPU utilization gauge at 5%
    path3 = engine.generate_utilization_bar(
        label="Enterprise Average",
        percentage=5.0,
        title="GPU Utilization Rate",
        save_path=str(base_dir / "test_utilization_bar.png"),
        context_text="Most GPUs sit idle — 95% capacity wasted",
    )
    print(f"  [3/4] Utilization bar: {path3}")

    # Test 4: Comparison bar — AI vs non-AI vulnerability rates
    path4 = engine.generate_comparison_bar(
        categories=["Vulnerability Rate (%)"],
        values_left=[47],
        values_right=[12],
        title="Code Vulnerability Comparison",
        save_path=str(base_dir / "test_comparison_bar.png"),
        label_left="AI-Generated Code",
        label_right="Human-Generated Code",
        colors=[BUBBLE_ZONE, GRAY_MEDIUM],
    )
    print(f"  [4/4] Comparison bar: {path4}")

    print("\nAll 4 test charts generated successfully.")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Battle card mini-chart engine"
    )
    parser.add_argument(
        "--test",
        action="store_true",
        help="Generate 4 test charts demonstrating each chart type",
    )
    args = parser.parse_args()

    if args.test:
        _run_tests()
    else:
        parser.print_help()
