"""离线色准图 Demo。

运行后会在 tools/demo_outputs/ 下生成一张 PNG，
用于在没有 UCD 设备时预览当前色准图表的 Calman 风格布局。
"""

from __future__ import annotations

import argparse
import math
import sys
from pathlib import Path

import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams["font.family"] = ["sans-serif"]
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False

REPO_ROOT = Path(__file__).resolve().parents[1]
if str(REPO_ROOT) not in sys.path:
    sys.path.insert(0, str(REPO_ROOT))

from app.plots.plot_accuracy import plot_accuracy
from app.tests.color_accuracy import (
    calculate_delta_e_2000,
    get_accuracy_color_standards,
)


COLOR_NAMES = [
    "White",
    "Gray 80",
    "Gray 65",
    "Gray 50",
    "Gray 35",
    "Dark Skin",
    "Light Skin",
    "Blue Sky",
    "Foliage",
    "Blue Flower",
    "Bluish Green",
    "Orange",
    "Purplish Blue",
    "Moderate Red",
    "Purple",
    "Yellow Green",
    "Orange Yellow",
    "Blue (Legacy)",
    "Green (Legacy)",
    "Red (Legacy)",
    "Yellow (Legacy)",
    "Magenta (Legacy)",
    "Cyan (Legacy)",
    "100% Red",
    "100% Green",
    "100% Blue",
    "100% Cyan",
    "100% Magenta",
    "100% Yellow",
]


class _DummyNotebook:
    def select(self, *_args, **_kwargs):
        return None


class _DummyCanvas:
    def draw(self):
        return None


class _DemoApp:
    def __init__(self, fig):
        self.accuracy_fig = fig
        self.accuracy_canvas = _DummyCanvas()
        self.chart_notebook = _DummyNotebook()
        self.accuracy_chart_frame = object()

    def get_test_type_name(self, test_type):
        mapping = {
            "sdr_movie": "SDR Movie",
            "hdr_movie": "HDR Movie",
            "screen_module": "屏模组",
        }
        return mapping.get(test_type, str(test_type))


def _build_demo_data(test_type: str = "sdr_movie"):
    standards = get_accuracy_color_standards(test_type)
    rng = np.random.default_rng(20260527)

    measured = []
    color_patches = []
    delta_e_values = []

    for idx, name in enumerate(COLOR_NAMES):
        sx, sy = standards[name]

        # 构造一些“看起来像真实测量”的偏移：
        # 大部分点轻微偏移，少数点更明显，便于看出方向和等级差异。
        if idx < 5:
            offset_scale = 0.0012
        elif idx < 23:
            offset_scale = 0.0028
        else:
            offset_scale = 0.0045

        angle = rng.uniform(0, 2 * math.pi)
        radius = offset_scale * (0.55 + 0.85 * rng.random())
        dx = math.cos(angle) * radius
        dy = math.sin(angle) * radius

        # 为了让图上连线不完全随机，给部分饱和色再加一点定向偏移。
        if idx >= 23:
            dx += 0.002 * (1 if idx % 2 == 0 else -1)
            dy += 0.0015 * (1 if idx % 3 == 0 else -1)

        mx = min(max(sx + dx, 0.0), 0.8)
        my = min(max(sy + dy, 0.0), 0.9)

        # 亮度也做一点微小变化，避免所有点完全同一层。
        measured_lv = 70.0 + rng.normal(0, 4.0)
        measured_lv = max(measured_lv, 1.0)

        delta_e = calculate_delta_e_2000(mx, my, measured_lv, sx, sy)

        measured.append((mx, my, measured_lv))
        color_patches.append(name)
        delta_e_values.append(delta_e)

    avg_delta_e = float(np.mean(delta_e_values))
    max_delta_e = float(np.max(delta_e_values))
    min_delta_e = float(np.min(delta_e_values))

    return {
        "color_patches": color_patches,
        "delta_e_values": delta_e_values,
        "color_measurements": measured,
        "avg_delta_e": avg_delta_e,
        "max_delta_e": max_delta_e,
        "min_delta_e": min_delta_e,
        "excellent_count": sum(1 for value in delta_e_values if value < 3),
        "good_count": sum(1 for value in delta_e_values if 3 <= value < 5),
        "poor_count": sum(1 for value in delta_e_values if value >= 5),
        "avg_delta_e_gray": float(np.mean(delta_e_values[0:5])),
        "avg_delta_e_colorchecker": float(np.mean(delta_e_values[5:23])),
        "avg_delta_e_saturated": float(np.mean(delta_e_values[23:29])),
        "target_gamma": 2.2,
    }


def main():
    parser = argparse.ArgumentParser(description="Generate an offline color accuracy demo PNG.")
    parser.add_argument(
        "--output",
        type=Path,
        default=Path(__file__).resolve().parent / "demo_outputs" / "accuracy_demo.png",
        help="Output PNG path.",
    )
    parser.add_argument(
        "--test-type",
        choices=["sdr_movie", "hdr_movie", "screen_module"],
        default="sdr_movie",
        help="Test type used for the title and standard color set.",
    )
    args = parser.parse_args()

    args.output.parent.mkdir(parents=True, exist_ok=True)

    fig = plt.Figure(figsize=(14, 8), dpi=120, tight_layout=False)
    app = _DemoApp(fig)
    accuracy_data = _build_demo_data(args.test_type)

    plot_accuracy(app, accuracy_data, args.test_type)
    fig.savefig(args.output, dpi=220)

    print(f"Saved demo image to: {args.output}")


if __name__ == "__main__":
    main()