"""
HPCI 4軸 レーダーチャート生成。

軸配置 (本体プロンプト §11 固定):
  12時方向: C (Concentration)
  3時方向:  R (Top-5 concentration, 旧称 Repeat)
  6時方向:  D (Density)
  9時方向:  S (Self-involvement)
  時計回り C → R → D → S

描画には normalized 値 (0-100) を使用する。元値ではない。
"""
from __future__ import annotations

import argparse
import base64
import json
import sys
from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

# このスクリプトを直接実行できるよう sys.path を追加
sys.path.insert(0, str(Path(__file__).resolve().parent))

from compute_hpci import ALBUM_REGISTRY, compute_hpci, format_value, write_json_atomic  # noqa: E402


def generate_radar_chart(
    result: dict,
    out_png: Path,
    out_base64: Path | None = None,
) -> None:
    axes_norm = result["axes_normalized"]
    # 12時C / 3時R / 6時D / 9時S を実現するため、matplotlib の極座標系で:
    #   theta = pi/2 (12時) を起点に、時計回り (-direction) で配置
    labels = ["C\nConcentration", "R\nTop-5 concentration", "D\nDensity", "S\nSelf-involvement"]
    values = [
        axes_norm["C_axis_normalized"],
        axes_norm["R_axis_normalized"],
        axes_norm["D_axis_normalized"],
        axes_norm["S_axis_normalized"],
    ]
    # 元値も表示用に取得
    raw = result["axes"]
    raw_values = [raw["C_axis"], raw["R_axis"], raw["D_axis"], raw["S_axis"]]
    raw_units = ["(0-10000)", "(%)", "(persons/track)", "(%)"]

    n = len(labels)
    # set_theta_zero_location("N") で 12時 = 0、set_theta_direction(-1) で時計回り。
    # この設定下では theta = 2π*i/n をそのまま使えば:
    #   i=0 → 12時(C), i=1 → 3時(R), i=2 → 6時(D), i=3 → 9時(S)
    theta = [2*np.pi*i/n for i in range(n)]
    theta_closed = theta + [theta[0]]
    values_closed = values + [values[0]]

    fig, ax = plt.subplots(
        figsize=(12, 12), dpi=100,
        subplot_kw={"projection": "polar"},
    )
    ax.set_theta_zero_location("N")  # 12時=0度
    ax.set_theta_direction(-1)       # 時計回り
    ax.spines["polar"].set_visible(False)  # 外側のラベル用余白を目盛りと見せない

    # 軸の目盛り (0-100 を 20刻みで)
    ax.set_ylim(0, 100)
    ax.set_yticks([20, 40, 60, 80, 100])
    ax.set_yticklabels(["20", "40", "60", "80", "100"], fontsize=9, color="#666")
    ax.set_rlabel_position(45)

    # データ描画
    ax.plot(theta_closed, values_closed, linewidth=2.5, color="#1a1a1a")
    ax.fill(theta_closed, values_closed, alpha=0.20, color="#1a1a1a")

    # 各軸の数値ラベル (実値)
    for angle, label, raw_v, unit in zip(theta, labels, raw_values, raw_units):
        # 左右の軸も名称と原値を縦に並べ、同じ水平線上で重ならないようにする。
        alignment = "left" if label.startswith("R") else "right" if label.startswith("S") else "center"
        ax.text(
            angle, 117, f"{label}\n{format_value(raw_v)} {unit}",
            ha=alignment, va="center", fontsize=11, fontweight="bold", linespacing=1.5,
        )

    # デフォルト軸ラベルは消す (上で手動配置したので)
    ax.set_xticks(theta)
    ax.set_xticklabels([""] * n)
    ax.set_ylim(0, 130)  # ラベルが入るよう外側に余裕

    # タイトル
    title = result.get("chart_title") or f"{result['artist']} — {result['title']} ({result['release_year']})"
    subtitle = "HPCI Production Constellation Index (4-axis)"
    fig.suptitle(title, fontsize=18, fontweight="bold", y=0.97)
    ax.set_title(subtitle, fontsize=12, color="#555", pad=30)

    # 凡例的なフッター
    footer = (
        f"total_tracks={result['total_tracks']}  "
        f"collaborators={result['intermediate_values']['collaborators_total_count']}  "
        f"mentions={result['intermediate_values']['total_credit_mentions']}"
    )
    fig.text(0.5, 0.03, footer, ha="center", fontsize=10, color="#666")
    fig.text(0.5, 0.01, "HIPHOPCs / hpci_constellation", ha="center", fontsize=8, color="#999")

    out_png.parent.mkdir(parents=True, exist_ok=True)
    fig.savefig(out_png, dpi=100, bbox_inches="tight", facecolor="white")
    plt.close(fig)

    if out_base64:
        with out_png.open("rb") as f:
            b64 = base64.b64encode(f.read()).decode("ascii")
        out_base64.write_text(f"data:image/png;base64,{b64}\n", encoding="utf-8")


def generate_overview(out_png: Path, out_json: Path) -> None:
    """固定5人×5曲の合成CSVを通常の算出関数へ渡して概要図を描く。"""
    import csv
    import tempfile
    with tempfile.TemporaryDirectory() as folder:
        input_path = Path(folder) / "fixed_five_input.csv"
        with input_path.open("w", encoding="utf-8", newline="") as stream:
            writer = csv.writer(stream)
            writer.writerow(["album_slug", "track_no", "title", "writers", "producers", "sampling_rights_holders", "notes"])
            for number in range(1, 6):
                writer.writerow(["fixed_five", number, f"Track {number}", "Drake; Person B; Person C; Person D; Person E", "", "", "SYNTHETIC"])
        result = compute_hpci("fixed_five", "Drake", "Synthetic fixed five", 2026, input_path)
    assert result["axes"] == {"C_axis": 2000.0, "R_axis": 100.0, "D_axis": 5.0, "S_axis": 100.0}
    result["artist"] = "Synthetic example"
    result["title"] = "Same 5 people on all 5 tracks (one is the artist)"
    result["chart_title"] = "Synthetic example: same 5 people on all 5 tracks"
    write_json_atomic(out_json, result)
    generate_radar_chart(result, out_png)


def generate_reading_guide(out_png: Path) -> None:
    """指標の用途を示す図。作品評価や固定メンバーを集約値から推定しない。"""
    fig, ax = plt.subplots(figsize=(12, 7), dpi=140)
    ax.set_axis_off()
    fig.suptitle("Reading HPCI", fontsize=24, fontweight="bold", y=0.95)
    items = [
        ("1  C / Concentration", "Distribution of mentions across all credited people"),
        ("2  R / Top-5 concentration", "Share of all mentions held by the album's top five people"),
        ("3  D / Density", "Average number of credited people per track"),
        ("4  S / Self-involvement", "Share of tracks crediting the artist as writer or producer"),
    ]
    for index, (heading, description) in enumerate(items):
        y = 0.86 - index * 0.20
        ax.text(0.06, y, heading, transform=ax.transAxes, fontsize=17, fontweight="bold")
        ax.text(0.06, y - 0.065, description, transform=ax.transAxes, fontsize=13)
    fig.text(0.08, 0.10, "RP and mean Jaccard are supporting measures of overlap.", fontsize=12)
    fig.text(0.08, 0.055, "To identify recurring members, inspect the credits for each track.", fontsize=12)
    out_png.parent.mkdir(parents=True, exist_ok=True)
    fig.savefig(out_png, facecolor="white", bbox_inches="tight")
    plt.close(fig)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--album")
    parser.add_argument("--overview", action="store_true", help="固定5人×5曲の合成例を生成")
    parser.add_argument("--reading-guide", action="store_true", help="読み方の図を生成")
    parser.add_argument("--json", default=None, help="入力JSONパス")
    parser.add_argument("--out-png", default=None)
    parser.add_argument("--out-base64", default=None)
    args = parser.parse_args()

    if args.reading_guide:
        out_png = Path(args.out_png) if args.out_png else Path("hpci-reading-guide-v5.png")
        generate_reading_guide(out_png)
        print(f"Chart: {out_png}")
        return 0

    if args.overview:
        out_png = Path(args.out_png) if args.out_png else Path("hpci-overview-v5.png")
        generate_overview(out_png, out_png.with_suffix(".json"))
        print(f"Chart: {out_png}")
        return 0

    if args.album not in ALBUM_REGISTRY:
        print(
            f"ERROR: album '{args.album}' is not in ALBUM_REGISTRY.\n"
            f"Available albums: {sorted(ALBUM_REGISTRY.keys())}",
            file=sys.stderr,
        )
        return 2

    project_root = Path(__file__).resolve().parent.parent
    json_path = Path(args.json) if args.json else project_root / "data" / "credits" / f"{args.album}.json"
    out_png = Path(args.out_png) if args.out_png else project_root / "output" / f"{args.album}_radar.png"
    out_base64 = Path(args.out_base64) if args.out_base64 else project_root / "output" / f"{args.album}_radar_base64.txt"

    if not json_path.exists():
        print(f"ERROR: JSON not found: {json_path}", file=sys.stderr)
        return 2

    result = json.loads(json_path.read_text(encoding="utf-8"))
    generate_radar_chart(result, out_png, out_base64)
    print(f"✓ Chart: {out_png}")
    print(f"✓ Base64: {out_base64}")
    return 0


if __name__ == "__main__":
    sys.exit(main())
