"""記事B 最小実験の共通部品：データ構造の定義と、架空データの投入（改訂版 rev1）。

保存先は SQLite（ファイルにもメモリにも置ける軽量なデータベース）。
ここでは毎回メモリ上に作り、テストごとに作り直す。

改訂点:
  - 外部キー検査（REFERENCES で宣言した関係を保存先が守る仕組み）を接続ごとに有効化し、実際に 1 になったことを確認する。
    SQLite では既定で無効なので、宣言を書いただけでは守られない。
  - 接続は「明示的な確定・取消を使う」設定（isolation_level が None でない）で作る。
"""
import sqlite3
from dataclasses import dataclass


@dataclass
class ApprovalResult:
    ok: bool
    reason: str


SCHEMA = """
CREATE TABLE users (
    id   TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    role TEXT NOT NULL            -- 依頼者 / 承認者 / 運用管理者（この最小実験では1人1役割）
);
CREATE TABLE requests (
    id           TEXT PRIMARY KEY,
    requester_id TEXT NOT NULL REFERENCES users(id),
    title        TEXT NOT NULL,
    body         TEXT NOT NULL,
    state        TEXT NOT NULL,   -- 下書き / 提出済み / 差戻し / 承認済み
    approver_id  TEXT REFERENCES users(id)
);
CREATE TABLE history (
    seq        INTEGER PRIMARY KEY AUTOINCREMENT,
    request_id TEXT NOT NULL REFERENCES requests(id),
    action     TEXT NOT NULL,     -- 提出 / 再提出 / 承認 / 差戻し
    actor_id   TEXT NOT NULL REFERENCES users(id),
    at         TEXT NOT NULL,     -- ISO 8601（UTC）
    note       TEXT
);
"""

# 架空の設定：みらい業務サービスの利用者
USERS = [
    ("u-sato",      "佐藤（依頼者）",   "依頼者"),
    ("u-tanaka",    "田中（依頼者）",   "依頼者"),
    ("u-suzuki",    "鈴木（承認者）",   "承認者"),
    ("u-takahashi", "高橋（承認者）",   "承認者"),
    ("u-admin",     "運用管理者",       "運用管理者"),
]

# 架空の依頼データ。approver_id は「割り当てられた承認者」
REQUESTS = [
    # id,       requester,  title,                  body,              state,     approver
    ("REQ-A01", "u-sato",   "会議室プロジェクタ手配", "10/3 14時 第2会議室", "提出済み", "u-suzuki"),
    ("REQ-A02", "u-sato",   "名刺の追加発注",         "100枚",               "下書き",   "u-suzuki"),
    ("REQ-A03", "u-suzuki", "備品棚の移設",           "3階から2階へ",        "提出済み", "u-suzuki"),   # 依頼者=承認者（自己承認の検査用の異常データ）
    ("REQ-A04", "u-sato",   "社用車の予約",           "10/5 終日",           "承認済み", "u-takahashi"),
    ("REQ-A05", "u-tanaka", "来客用駐車場の確保",     "10/7 午前",           "提出済み", "u-admin"),    # 承認者でない人を誤って割当（役割検査用の異常データ）
]

HISTORY = [
    ("REQ-A01", "提出", "u-sato",      "2026-09-10T01:00:00+00:00", None),
    ("REQ-A03", "提出", "u-suzuki",    "2026-09-10T02:00:00+00:00", None),
    ("REQ-A04", "提出", "u-sato",      "2026-09-09T01:00:00+00:00", None),
    ("REQ-A04", "承認", "u-takahashi", "2026-09-09T05:00:00+00:00", None),
    ("REQ-A05", "提出", "u-tanaka",    "2026-09-11T01:00:00+00:00", None),
]


def fresh_connection() -> sqlite3.Connection:
    conn = sqlite3.connect(":memory:")
    conn.execute("PRAGMA foreign_keys = ON")
    fk = conn.execute("PRAGMA foreign_keys").fetchone()[0]
    if fk != 1:
        raise RuntimeError(f"外部キー検査を有効にできなかった（PRAGMA foreign_keys = {fk}）")
    conn.executescript(SCHEMA)
    conn.executemany("INSERT INTO users VALUES (?, ?, ?)", USERS)
    conn.executemany("INSERT INTO requests VALUES (?, ?, ?, ?, ?, ?)", REQUESTS)
    conn.executemany("INSERT INTO history (request_id, action, actor_id, at, note) VALUES (?, ?, ?, ?, ?)", HISTORY)
    conn.commit()
    return conn


def state_of(conn, request_id):
    return conn.execute("SELECT state FROM requests WHERE id = ?", (request_id,)).fetchone()[0]


def history_of(conn, request_id, action=None):
    if action is None:
        return conn.execute(
            "SELECT action, actor_id, at, note FROM history WHERE request_id = ? ORDER BY seq", (request_id,)
        ).fetchall()
    return conn.execute(
        "SELECT action, actor_id, at, note FROM history WHERE request_id = ? AND action = ? ORDER BY seq",
        (request_id, action),
    ).fetchall()


def full_snapshot(conn):
    """依頼と履歴の全行。拒否時に『何も変わっていない』ことを確かめるために使う。"""
    reqs = conn.execute("SELECT id, requester_id, title, body, state, approver_id FROM requests ORDER BY id").fetchall()
    hist = conn.execute("SELECT seq, request_id, action, actor_id, at, note FROM history ORDER BY seq").fetchall()
    return (reqs, hist)
