"""承認処理の最小例 v1 —【説明用の失敗例】

記事B（SAMPLE-B）で使う、意図的に不備を入れたバージョンです。
「AIが最初に出してきた初稿」という設定ですが、実際のAIの出力を観測したものではなく、
教材のために Claude Code が意図して不備を入れて作成した説明用の例です（改訂版でも中身は変えていない）。

不備（意図的）:
  - 承認者の割当を確認していない（REQ-003）
  - 自己承認を防いでいない（REQ-003）
  - 対象の状態が「提出済み」かを確認していない（REQ-003 / REQ-006）
  - 状態変更と履歴追加を別々に確定しており、途中で失敗すると片方だけ残る（REQ-007）

本人確認（認証）は行わず、操作者IDを引数で受け取る「固定値の代用」です。
これは実際の認証機能を実装・検証した証拠にはなりません。
"""
import sqlite3
from datetime import datetime, timezone

from common import ApprovalResult

clock = None  # テストから固定時刻を注入するための差込み口（None なら現在時刻）


def _now() -> str:
    if clock is not None:
        return clock()
    return datetime.now(timezone.utc).isoformat(timespec="seconds")


def approve(conn: sqlite3.Connection, request_id: str, actor_id: str, _fault=None) -> ApprovalResult:
    """依頼を承認する（説明用の失敗例）。

    _fault: テスト専用。状態更新の後、履歴追加の前に呼ばれる。
            例外を投げれば「途中失敗」を再現できる。
    """
    row = conn.execute("SELECT state FROM requests WHERE id = ?", (request_id,)).fetchone()
    if row is None:
        return ApprovalResult(ok=False, reason="依頼が存在しない")

    # 不備: 誰が承認しようとしているかを一切確認していない。状態も確認していない。
    conn.execute("UPDATE requests SET state = '承認済み' WHERE id = ?", (request_id,))
    conn.commit()  # 不備: ここで状態変更だけ先に確定してしまう

    if _fault is not None:
        _fault()

    conn.execute(
        "INSERT INTO history (request_id, action, actor_id, at) VALUES (?, '承認', ?, ?)",
        (request_id, actor_id, _now()),
    )
    conn.commit()
    return ApprovalResult(ok=True, reason="承認しました")


def send_back(conn: sqlite3.Connection, request_id: str, actor_id: str, reason: str) -> ApprovalResult:
    """依頼を差し戻す（説明用の失敗例）。理由の有無を確認していない（REQ-004）。"""
    conn.execute("UPDATE requests SET state = '差戻し' WHERE id = ?", (request_id,))
    conn.execute(
        "INSERT INTO history (request_id, action, actor_id, at, note) VALUES (?, '差戻し', ?, ?, ?)",
        (request_id, actor_id, _now(), reason),
    )
    conn.commit()
    return ApprovalResult(ok=True, reason="差し戻しました")
