"""目録の集計（`tiasdata stats`．SPEC_03「CLI」）.

件数と所見の値（舌色の slug 等）だけを返す．対応表（`identity.sqlite`）は開かない．
"""

import json
import sqlite3
from collections import Counter
from dataclasses import dataclass

from tiasdata import catalog


@dataclass(frozen=True)
class AnnotationStats:
    """所見の種類ごとの集計．

    Attributes:
        total: 有効な所見（訂正されていないもの）の数．
        by_field: 値の項目 → 値 → 件数（例: `label` → `red` → 120）．
        by_value: 値の組み合わせ（`項目=値` を `, ` でつないだもの）→ 件数．
    """

    total: int
    by_field: dict[str, dict[str, int]]
    by_value: dict[str, int]


@dataclass(frozen=True)
class CatalogStats:
    """目録の集計．

    Attributes:
        subjects: 症例の数．
        captures: 撮影の数．
        subjects_with_multiple_captures: 撮影を 2 つ以上持つ症例の数．
        assets_by_kind: ファイルの種類 → ファイル数．
        annotations: 所見の種類 → 集計．
        superseded_annotations: 訂正された所見の数．
    """

    subjects: int
    captures: int
    subjects_with_multiple_captures: int
    assets_by_kind: dict[str, int]
    annotations: dict[str, AnnotationStats]
    superseded_annotations: int


def summarize_annotation_values(values: dict[str, int]) -> AnnotationStats:
    """所見の値（JSON の文字列）ごとの件数を，項目ごと・組み合わせごとの件数にまとめる．

    Args:
        values: 値の JSON → 件数（同じ種類の所見）．

    Returns:
        集計．項目・値は名前の順に並べる．
    """
    by_field: dict[str, Counter[str]] = {}
    by_value: Counter[str] = Counter()
    for value_json, count in values.items():
        value = json.loads(value_json)
        if not isinstance(value, dict):
            by_value[value_json] += count
            continue
        for field, field_value in value.items():
            by_field.setdefault(field, Counter())[_text(field_value)] += count
        by_value[", ".join(f"{k}={_text(v)}" for k, v in sorted(value.items()))] += count
    return AnnotationStats(
        total=sum(values.values()),
        by_field={field: dict(sorted(c.items())) for field, c in sorted(by_field.items())},
        by_value=dict(sorted(by_value.items())),
    )


def _text(value: object) -> str:
    return value if isinstance(value, str) else json.dumps(value, ensure_ascii=False)


def collect_stats(conn: sqlite3.Connection) -> CatalogStats:
    """目録を集計する．

    Args:
        conn: 目録への接続（スキーマ最新）．

    Returns:
        集計．
    """
    return CatalogStats(
        subjects=catalog.count_subjects(conn),
        captures=catalog.count_captures(conn),
        subjects_with_multiple_captures=catalog.count_subjects_with_multiple_captures(conn),
        assets_by_kind=catalog.count_assets_by_kind(conn),
        annotations={
            kind: summarize_annotation_values(values)
            for kind, values in catalog.count_annotation_values(conn).items()
        },
        superseded_annotations=catalog.count_superseded_annotations(conn),
    )
