"""所見の種類 `review`（要確認の印）の値の型（SPEC_02「kinds」）.

取り込み元のデータに，基盤では正解を決められない問題（同じ写真の重複・患者 ID やラベルの
食い違い等）があるものに付ける．取り込みでは要確認リスト（`reviews/<取り込み元の名前>.toml`）
から付ける（SPEC_03「要確認リスト」）．
"""

from datetime import date

from pydantic import BaseModel, ConfigDict, Field, field_validator

# 所見の種類名（kinds 表の行は catalog/0002_review_kind.sql）
REVIEW_KIND = "review"

_DATE_PATTERN = r"^[0-9]{4}-[0-9]{2}-[0-9]{2}$"


class Review(BaseModel):
    """要確認の印の値（`{"reason": ..., "resolve": ..., "since": ..., "numbers": [...]}`）．

    Attributes:
        reason: 要確認にした理由．
        resolve: 確かめる方法．
        since: 要確認にした日（`YYYY-MM-DD`）．
        numbers: 取り込み元での番号（昇順・重複なし・1 以上）．同じ中身のファイルが複数の番号に
            あったときは，そのすべての番号．
    """

    # 未知のキーは拒否する（綴りの誤りで値が黙って欠けるのを防ぐ）
    model_config = ConfigDict(extra="forbid", frozen=True, strict=True)

    reason: str = Field(min_length=1)
    resolve: str = Field(min_length=1)
    # JSON から読んだ値と同じ形で比べられるように，日付は文字列のまま持つ
    since: str = Field(pattern=_DATE_PATTERN)
    numbers: list[int] = Field(min_length=1)

    @field_validator("since")
    @classmethod
    def _valid_date(cls, value: str) -> str:
        date.fromisoformat(value)
        return value

    @field_validator("numbers")
    @classmethod
    def _sorted_unique_positive(cls, value: list[int]) -> list[int]:
        # 同じ印が常に同じ JSON になるように，並びを固定する
        if any(number < 1 for number in value):
            raise ValueError("numbers は 1 以上")
        if value != sorted(set(value)):
            raise ValueError("numbers は昇順・重複なしで並べる")
        return value
