from __future__ import annotations

import json
from functools import lru_cache
from pathlib import Path
from typing import Any

TRIGRAM_NAMES = {
    (1, 1, 1): "乾",
    (1, 1, 0): "兑",
    (1, 0, 1): "离",
    (1, 0, 0): "震",
    (0, 1, 1): "巽",
    (0, 1, 0): "坎",
    (0, 0, 1): "艮",
    (0, 0, 0): "坤",
}
LINE_POSITIONS = ("初爻", "二爻", "三爻", "四爻", "五爻", "上爻")


def from_lines(values: list[int], data_path: Path) -> dict[str, Any]:
    if len(values) != 6 or any(value not in {6, 7, 8, 9} for value in values):
        raise ValueError("六爻必须由六、七、八、九组成，且从初爻到上爻排列。")
    bits = tuple(1 if value % 2 else 0 for value in values)
    transformed_values = [7 if value == 6 else 8 if value == 9 else value for value in values]
    transformed_bits = tuple(1 if value % 2 else 0 for value in transformed_values)
    data = _load(data_path)
    primary = data.get(str(bits))
    transformed = data.get(str(transformed_bits))
    if not primary or not transformed:
        raise ValueError("卦象数据不完整。")
    line_texts = list(primary["lines"].values())
    lines = [
        {
            "position": index + 1,
            "position_name": LINE_POSITIONS[index],
            "value": value,
            "yin_yang": "阳" if value % 2 else "阴",
            "moving": value in {6, 9},
            "line_name": line_texts[index]["name"],
            "text": line_texts[index]["text"],
            "image": line_texts[index].get("image") or "",
        }
        for index, value in enumerate(values)
    ]
    return {
        "name": primary["name"],
        "text": primary["text"],
        "image": primary.get("image") or "",
        "inner_trigram": TRIGRAM_NAMES[bits[:3]],
        "outer_trigram": TRIGRAM_NAMES[bits[3:]],
        "lines": lines,
        "moving_lines": [index + 1 for index, value in enumerate(values) if value in {6, 9}],
        "transformed": {
            "name": transformed["name"],
            "text": transformed["text"],
            "image": transformed.get("image") or "",
            "inner_trigram": TRIGRAM_NAMES[transformed_bits[:3]],
            "outer_trigram": TRIGRAM_NAMES[transformed_bits[3:]],
        },
    }


def line_for_score(score: float) -> int:
    if score >= 0.72:
        return 9
    if score >= 0:
        return 7
    if score <= -0.72:
        return 6
    return 8


@lru_cache(maxsize=2)
def _load(path: Path) -> dict[str, Any]:
    payload = json.loads(path.read_text(encoding="utf-8"))
    return payload.get("hexagrams", payload)
