"""対応表（`identity.sqlite`．実際の患者 ID ↔ 研究用 ID）の操作.

対応表を開くのは取り込みの処理だけにする（coding-style.md「臨床データを扱うコードの規則」）．
目録の接続に `ATTACH` して使い，目録と対応表への登録を 1 つのトランザクションにまとめる
（途中で失敗したら両方とも何も残らないようにするため）．

ここで扱う患者 ID は例外メッセージ・ログに出さない．
"""

import sqlite3
from pathlib import Path

from tiasdata.catalog.migrate import require_latest
from tiasdata.catalog.records import parse_id_number

# 目録の接続の中での対応表のスキーマ名
IDENTITY_SCHEMA = "identity"


def attach_identity(conn: sqlite3.Connection, path: Path) -> None:
    """目録の接続に対応表を `identity` として ATTACH する．

    対応表のファイルが無いときは作らずに停止する（`tiasdata init` の前に誤って空の対応表を
    作らないため）．スキーマが最新でなければ停止する．

    Args:
        conn: `connect()` で開いた目録の接続（トランザクションの外であること）．
        path: 対応表のパス．

    Raises:
        ValueError: 対応表が無い，開けない，またはスキーマが最新でない．
    """
    if not path.is_file():
        raise ValueError("対応表が無い．先に `tiasdata init` を実行する")
    # connect() は URI を有効にして開くため，ATTACH でも mode=rw（無ければ作らない）が効く
    uri = f"{path.resolve().as_uri()}?mode=rw"
    try:
        conn.execute(f"ATTACH DATABASE ? AS {IDENTITY_SCHEMA}", (uri,))
    except sqlite3.OperationalError as e:
        raise ValueError(f"対応表を開けない: {e}") from e
    require_latest(conn, "identity", schema=IDENTITY_SCHEMA)


def find_subject_id(conn: sqlite3.Connection, patient_key: str) -> str | None:
    """患者 ID に対応する研究用 ID を引く（無ければ None）．"""
    row = conn.execute(
        f"SELECT subject_id FROM {IDENTITY_SCHEMA}.identity_map WHERE patient_key = ?",
        (patient_key,),
    ).fetchone()
    return row[0] if row else None


def max_identity_subject_number(conn: sqlite3.Connection) -> int:
    """対応表の研究用 ID の最大の番号を返す（無ければ 0）．

    目録を作り直した場合等に，対応表にだけある研究用 ID と重ならないようにするため．
    """
    (value,) = conn.execute(
        f"SELECT MAX(subject_id) FROM {IDENTITY_SCHEMA}.identity_map"
    ).fetchone()
    return parse_id_number(value)


def insert_identity(
    conn: sqlite3.Connection, patient_key: str, subject_id: str, created_at: str
) -> None:
    """患者 ID と研究用 ID の対応を登録する．"""
    conn.execute(
        f"INSERT INTO {IDENTITY_SCHEMA}.identity_map (patient_key, subject_id, created_at)"
        " VALUES (?, ?, ?)",
        (patient_key, subject_id, created_at),
    )
