"""ファイルの種類・所見の種類の値の型.

種類の行（`kinds` 表）はマイグレーションで足し，所見の値の型はここに足す
（SPEC_02「拡張の例」）．所見の値は目録に保存する前にここの型で検証する．
"""

import json
from typing import Any

from pydantic import BaseModel

from tiasdata.kinds.review import REVIEW_KIND, Review
from tiasdata.kinds.tongue_color import TongueColor

# 所見の種類名 → 値の型
ANNOTATION_VALUE_TYPES: dict[str, type[BaseModel]] = {
    REVIEW_KIND: Review,
    "tongue_color": TongueColor,
}


def annotation_value_type(kind: str) -> type[BaseModel]:
    """所見の種類名から値の型を引く．

    Args:
        kind: 所見の種類名（例: `tongue_color`）．

    Returns:
        値の型（pydantic のモデル）．

    Raises:
        ValueError: 値の型が定義されていない種類．
    """
    try:
        return ANNOTATION_VALUE_TYPES[kind]
    except KeyError:
        raise ValueError(f"所見の種類 '{kind}' の値の型が定義されていない") from None


def validate_annotation_value(kind: str, value: dict[str, Any]) -> BaseModel:
    """所見の値を種類の型で検証する．

    Args:
        kind: 所見の種類名．
        value: 値（JSON から読んだ辞書等）．

    Returns:
        検証済みの値．

    Raises:
        ValueError: 値の型が定義されていない種類．
        pydantic.ValidationError: 値が型に合わない（未知のキー・未知の値・無効な組み合わせ）．
    """
    return annotation_value_type(kind).model_validate(value)


def dump_annotation_value(value: BaseModel) -> str:
    """検証済みの所見の値を，目録に保存する JSON の文字列にする．

    キーの順を固定し空白を入れない（同じ値が常に同じ文字列になるようにするため）．

    Args:
        value: 検証済みの値．

    Returns:
        JSON の文字列．
    """
    return json.dumps(value.model_dump(mode="json"), sort_keys=True, separators=(",", ":"))


__all__ = [
    "ANNOTATION_VALUE_TYPES",
    "REVIEW_KIND",
    "Review",
    "TongueColor",
    "annotation_value_type",
    "dump_annotation_value",
    "validate_annotation_value",
]
