"""Visualisations temporelles des palettes de couleurs."""

from pathlib import Path
from typing import Dict, Iterable, List, Tuple

import matplotlib.pyplot as plt
import numpy as np

from lib.filesystem import ensure_parent_dir
from lib.milestones import load_milestones
from lib.rebrickable.stats import read_rows


def load_rows(path: Path) -> List[dict]:
    """Charge un CSV simple en mémoire sous forme de dictionnaires."""
    return read_rows(path)


def plot_translucent_share(timeline_path: Path, milestones_path: Path, destination_path: Path) -> None:
    """Trace l'évolution de la part de pièces translucides et du nombre de couleurs avec jalons."""
    rows = load_rows(timeline_path)
    milestones = load_milestones(milestones_path)
    years = [int(row["year"]) for row in rows]
    shares = [float(row["share_translucent"]) for row in rows]
    distinct_counts = [int(row["colors_distinct"]) for row in rows]

    fig, ax = plt.subplots(figsize=(13, 5.5))
    ax.plot(years, shares, color="#1f77b4", marker="o", linewidth=2.2, label="Part des translucides", zorder=3)
    ax.fill_between(years, shares, color="#1f77b4", alpha=0.15, zorder=2)
    ax.set_ylabel("Part translucide")
    ax.set_ylim(0, min(1.0, max(shares) * 1.1))
    ax.set_xlabel("Année")
    ax.grid(True, linestyle="--", alpha=0.3)
    ax2 = ax.twinx()
    ax2.plot(years, distinct_counts, color="#ff7f0e", marker="s", linewidth=1.8, label="Couleurs distinctes", zorder=3)
    ax2.set_ylabel("Nombre de couleurs distinctes")
    handles = [
        plt.Line2D([0], [0], color="#1f77b4", marker="o", label="Part des translucides"),
        plt.Line2D([0], [0], color="#ff7f0e", marker="s", label="Couleurs distinctes"),
    ]
    ax.legend(handles=handles, loc="upper left", bbox_to_anchor=(1.02, 1))
    ax.set_title("Evolution des palettes : translucides vs. diversité des couleurs")
    ax.set_xticks(years)
    ax.tick_params(axis="x", labelrotation=45)

    if milestones:
        min_year = min(years)
        max_year = max(years)
        milestones_in_range = sorted(
            [m for m in milestones if min_year <= m["year"] <= max_year],
            key=lambda m: (m["year"], m["description"]),
        )
        offset_step = 0.35
        offset_map: Dict[int, int] = {}
        top_limit = ax.get_ylim()[1] * 1.05
        for milestone in milestones_in_range:
            year = milestone["year"]
            count_for_year = offset_map.get(year, 0)
            offset_map[year] = count_for_year + 1
            horizontal_offset = offset_step * (count_for_year // 2 + 1)
            if count_for_year % 2 == 1:
                horizontal_offset *= -1
            text_x = year + horizontal_offset
            ax.axvline(year, color="#d62728", linestyle="--", linewidth=1, alpha=0.65, zorder=1)
            ax.text(
                text_x,
                top_limit,
                milestone["description"],
                rotation=90,
                verticalalignment="top",
                horizontalalignment="center",
                fontsize=8,
                color="#d62728",
            )
        ax.set_ylim(ax.get_ylim()[0], top_limit * (1 + max(offset_map.values(), default=0) * 0.02))
    ensure_parent_dir(destination_path)
    fig.tight_layout()
    fig.savefig(destination_path, dpi=160)
    plt.close(fig)


def build_heatmap_data(rows: Iterable[dict]) -> Tuple[List[int], List[str], np.ndarray]:
    """Construit les vecteurs année, labels de couleur et matrice de quantités."""
    years = sorted({int(row["year"]) for row in rows})
    color_totals: Dict[Tuple[str, str, str], int] = {}
    for row in rows:
        key = (row["color_name"], row["color_rgb"], row["is_translucent"])
        color_totals[key] = color_totals.get(key, 0) + int(row["quantity_total"])
    sorted_colors = sorted(
        color_totals.items(),
        key=lambda item: (-item[1], item[0][0], item[0][1]),
    )
    color_keys = [color for color, _ in sorted_colors]
    labels = [f"{name} ({'trans' if is_trans == 'true' else 'opaque'})" for name, _, is_trans in color_keys]
    matrix = np.zeros((len(color_keys), len(years)), dtype=float)
    index_by_year = {year: idx for idx, year in enumerate(years)}
    index_by_color = {color: idx for idx, color in enumerate(color_keys)}
    for row in rows:
        color_key = (row["color_name"], row["color_rgb"], row["is_translucent"])
        y_index = index_by_color[color_key]
        x_index = index_by_year[int(row["year"])]
        matrix[y_index, x_index] += int(row["quantity_total"])
    swatches = [
        {
            "name": name,
            "rgb": color_rgb,
            "is_translucent": is_trans,
            "display_color": f"#{color_rgb}",
        }
        for name, color_rgb, is_trans in color_keys
    ]
    return years, labels, matrix, swatches


def plot_colors_heatmap(
    matrix_path: Path,
    destination_path: Path,
    use_log_scale: bool = False,
    normalize_by_year: bool = False,
) -> None:
    """Génère une heatmap année × couleur avec pastilles (linéaire, log1p ou normalisée)."""
    rows = load_rows(matrix_path)
    years, labels, matrix, swatches = build_heatmap_data(rows)
    values = matrix
    if normalize_by_year:
        column_totals = matrix.sum(axis=0, keepdims=True)
        values = matrix / column_totals
    if use_log_scale:
        values = np.log1p(values)

    fig, ax = plt.subplots(figsize=(14, max(6, len(labels) * 0.26)))
    y_positions = np.arange(len(labels))
    heatmap = ax.imshow(values, aspect="auto", cmap="magma", origin="lower")
    ax.set_xticks(range(len(years)))
    ax.set_xticklabels(years, rotation=45)
    ax.set_yticks(range(len(labels)))
    ax.set_yticklabels(labels)
    facecolors = [swatch["display_color"] for swatch in swatches]
    edgecolors = ["#f2f2f2" if swatch["is_translucent"] == "true" else "#0b0b0b" for swatch in swatches]
    for y, face, edge in zip(y_positions, facecolors, edgecolors):
        ax.scatter(
            -0.8,
            y,
            s=150,
            marker="o",
            color=face,
            edgecolors=edge,
            linewidths=1.1,
            zorder=3,
            clip_on=False,
        )
    ax.set_xlim(-1.1, len(years) - 0.5)
    ax.set_xlabel("Année")
    if normalize_by_year:
        title_scale = "parts de couleur (par année)"
    else:
        title_scale = "log1p des quantités" if use_log_scale else "quantités totales"
    ax.set_title(f"Intensité des couleurs par année ({title_scale})")
    cbar = fig.colorbar(heatmap, ax=ax, shrink=0.82, pad=0.018)
    if normalize_by_year:
        cbar_label = "Part de la couleur (0-1)"
    elif use_log_scale:
        cbar_label = "log1p(quantité totale)"
    else:
        cbar_label = "quantité totale"
    cbar.set_label(cbar_label)
    ensure_parent_dir(destination_path)
    fig.subplots_adjust(left=0.26, right=0.97, bottom=0.08, top=0.94)
    fig.savefig(destination_path, dpi=170)
    plt.close(fig)
