"""Buffett Indicator Chart — US Market Cap / GDP"""

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt  # noqa: E402
import matplotlib.ticker as mticker  # noqa: E402
from pathlib import Path  # noqa: E402

from src.data.market_bubbles import buffett_indicator  # noqa: E402
from src.utils.styling import (  # noqa: E402
    BUBBLE_ZONE,
    EXPORT_DPI,
    FIGURE_SIZE_DEFAULT,
    NORMAL_ZONE,
    WARNING_ZONE,
    WHITE,
)


def _ensure_dir(path: str) -> Path:
    """Ensure output directory exists and return Path."""
    p = Path(path)
    p.mkdir(parents=True, exist_ok=True)
    return p


def _set_rc_safe() -> None:
    """Set rcParams without savefig.bbox=tight (avoids Python 3.14 RecursionError)."""
    plt.rcParams.update({
        "font.family": "DejaVu Sans",
        "font.size": 12,
        "figure.facecolor": WHITE,
        "figure.dpi": EXPORT_DPI,
        "axes.facecolor": "#fafafa",
        "axes.edgecolor": "#dddddd",
        "axes.grid": True,
        "axes.axisbelow": True,
        "grid.color": "#e0e0e0",
        "grid.linestyle": "-",
        "grid.linewidth": 0.5,
        "grid.alpha": 0.7,
        "xtick.labelsize": 10,
        "ytick.labelsize": 10,
        "axes.titlesize": 16,
        "axes.titleweight": "bold",
        "axes.labelsize": 12,
        "legend.fontsize": 9,
        "figure.titlesize": 16,
        "figure.titleweight": "bold",
        "savefig.dpi": EXPORT_DPI,
        "savefig.facecolor": WHITE,
        # NOTE: deliberately omitting savefig.bbox to avoid Python 3.14 +
        # matplotlib 3.9.2 deepcopy RecursionError with bbox_inches="tight"
    })


def plot_buffett_indicator() -> str:
    """Generate Buffett Indicator chart with danger threshold zones.

    Returns
    -------
    str
        Absolute path to the saved PNG file.
    """
    # ------------------------------------------------------------------
    # Data extraction
    # ------------------------------------------------------------------
    data = sorted(buffett_indicator, key=lambda d: d["year"])
    years = [d["year"] for d in data]
    values = [d["value"] for d in data]

    hist_years = [d["year"] for d in data if d["year"] < 2021]
    hist_vals = [d["value"] for d in data if d["year"] < 2021]
    comp_years = [d["year"] for d in data if d["year"] >= 2021]
    comp_vals = [d["value"] for d in data if d["year"] >= 2021]

    # ------------------------------------------------------------------
    # Figure setup
    # ------------------------------------------------------------------
    _set_rc_safe()
    fig, ax = plt.subplots(figsize=FIGURE_SIZE_DEFAULT, dpi=EXPORT_DPI)
    fig.set_facecolor(WHITE)
    ax.set_facecolor("#fafafa")

    # Spine cleanup
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["left"].set_color("#cccccc")
    ax.spines["bottom"].set_color("#cccccc")

    # ------------------------------------------------------------------
    # Shaded zones
    # ------------------------------------------------------------------
    ax.axhspan(0, 100, facecolor=NORMAL_ZONE, alpha=0.15, label="Normal (\u2264100%)")
    ax.axhspan(100, 200, facecolor=WARNING_ZONE, alpha=0.15, label="Warning (100\u2013200%)")
    ax.axhspan(200, 350, facecolor=BUBBLE_ZONE, alpha=0.15, label="Bubble (>200%)")

    # Composite data band
    ax.axvspan(2020.5, 2026.5, facecolor="gray", alpha=0.06,
               label="Estimated / composite data")

    # ------------------------------------------------------------------
    # Data lines
    # ------------------------------------------------------------------
    ax.plot(
        hist_years, hist_vals,
        color="#2c3e50",
        linewidth=2,
        marker="o",
        markersize=4,
        label="Historical (FRED / World Bank)",
        zorder=3,
    )
    ax.plot(
        comp_years, comp_vals,
        color="#e67e22",
        linewidth=2,
        linestyle="--",
        marker="s",
        markersize=5,
        label="Estimated / composite (2021\u20132026)",
        zorder=4,
    )

    # ------------------------------------------------------------------
    # Danger threshold line
    # ------------------------------------------------------------------
    ax.axhline(
        y=200,
        color=BUBBLE_ZONE,
        linewidth=2,
        linestyle="--",
        alpha=0.8,
        zorder=5,
    )
    ax.text(
        2011, 228,
        "Buffett danger threshold (200%)",
        fontsize=10,
        fontweight="bold",
        color=BUBBLE_ZONE,
        zorder=6,
    )

    # ------------------------------------------------------------------
    # Key peak labels (text-only)
    # ------------------------------------------------------------------
    peaks = [
        (1999, 153.43, "dot-com buildup"),
        (2000, 147.38, "peak"),
        (2020, 194.89, "pandemic bubble"),
        (2024, 216.3, "all-time high"),
        (2026, 219.0, "current"),
    ]

    for year, val, label in peaks:
        color = "#2c3e50" if year < 2021 else "#e67e22"
        ax.text(
            year,
            val + 14,
            f"{year}: {val:.1f}%\n({label})",
            fontsize=8.5,
            fontweight="bold",
            ha="center",
            color=color,
            zorder=7,
        )

    # ------------------------------------------------------------------
    # Title, subtitle, labels, legend
    # ------------------------------------------------------------------
    ax.set_title(
        "Buffett Indicator \u2014 US Market Cap / GDP \u2014 1975 to 2026",
        fontsize=16,
        fontweight="bold",
        pad=14,
    )
    ax.set_xlabel("Year", fontsize=12)
    ax.set_ylabel("Market Cap / GDP (%)", fontsize=12)

    ax.text(
        0.5, -0.18,
        "Warren Buffett's danger threshold: 200%  |  Current: 219%",
        transform=ax.transAxes,
        fontsize=11,
        ha="center",
        style="italic",
        color="#7f8c8d",
    )

    ax.set_xlim(1974, 2027)
    ax.set_yticks(range(0, 301, 50))
    ax.set_ylim(0, 300)
    ax.xaxis.set_major_locator(mticker.MultipleLocator(5))

    ax.legend(
        loc="upper left",
        fontsize=8,
        framealpha=0.9,
        edgecolor="#cccccc",
    )

    # ------------------------------------------------------------------
    # Save — direct savefig (no bbox_inches to avoid RecursionError)
    # ------------------------------------------------------------------
    output_dir = _ensure_dir("output/charts")
    output_path = output_dir / "02_buffett_indicator.png"

    fig.savefig(
        str(output_path),
        format="png",
        dpi=EXPORT_DPI,
        facecolor=fig.get_facecolor(),
        edgecolor="none",
    )

    plt.close(fig)
    return str(output_path)


def main() -> None:
    """Entry point for standalone execution."""
    path = plot_buffett_indicator()
    print(f"Chart saved: {path}")


if __name__ == "__main__":
    main()
