"""Approval item management — the governance layer for autonomous Timmy actions.

The GOLDEN_TIMMY constant is the single source of truth for whether Timmy
may act autonomously.  All features that want to take action must:

  1. Create an ApprovalItem
  2. Check GOLDEN_TIMMY
  3. If True  → wait for owner approval before executing
  4. If False → log the action and proceed (Dark Timmy mode)

Default is always True. The owner changes this intentionally.
"""

import sqlite3
import uuid
from collections.abc import Generator
from contextlib import closing, contextmanager
from dataclasses import dataclass
from datetime import UTC, datetime, timedelta
from pathlib import Path

# ---------------------------------------------------------------------------
# GOLDEN TIMMY RULE
# ---------------------------------------------------------------------------
GOLDEN_TIMMY = True
# When True:  no autonomous action executes without an approved ApprovalItem.
# When False: Dark Timmy mode — Timmy may act on his own judgment.
# Default is always True. Owner changes this intentionally.

# ---------------------------------------------------------------------------
# Persistence
# ---------------------------------------------------------------------------
_DEFAULT_DB = Path.home() / ".timmy" / "approvals.db"
_EXPIRY_DAYS = 7


@dataclass
class ApprovalItem:
    id: str
    title: str
    description: str
    proposed_action: str  # what Timmy wants to do
    impact: str  # "low" | "medium" | "high"
    created_at: datetime
    status: str  # "pending" | "approved" | "rejected"


@contextmanager
def _get_conn(db_path: Path = _DEFAULT_DB) -> Generator[sqlite3.Connection, None, None]:
    db_path.parent.mkdir(parents=True, exist_ok=True)
    with closing(sqlite3.connect(str(db_path))) as conn:
        conn.row_factory = sqlite3.Row
        conn.execute("""
            CREATE TABLE IF NOT EXISTS approval_items (
                id              TEXT PRIMARY KEY,
                title           TEXT NOT NULL,
                description     TEXT NOT NULL,
                proposed_action TEXT NOT NULL,
                impact          TEXT NOT NULL DEFAULT 'low',
                created_at      TEXT NOT NULL,
                status          TEXT NOT NULL DEFAULT 'pending'
            )
            """)
        conn.commit()
        yield conn


def _row_to_item(row: sqlite3.Row) -> ApprovalItem:
    return ApprovalItem(
        id=row["id"],
        title=row["title"],
        description=row["description"],
        proposed_action=row["proposed_action"],
        impact=row["impact"],
        created_at=datetime.fromisoformat(row["created_at"]),
        status=row["status"],
    )


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------


def create_item(
    title: str,
    description: str,
    proposed_action: str,
    impact: str = "low",
    db_path: Path = _DEFAULT_DB,
) -> ApprovalItem:
    """Create and persist a new approval item."""
    item = ApprovalItem(
        id=str(uuid.uuid4()),
        title=title,
        description=description,
        proposed_action=proposed_action,
        impact=impact,
        created_at=datetime.now(UTC),
        status="pending",
    )
    with _get_conn(db_path) as conn:
        conn.execute(
            """
            INSERT INTO approval_items
                (id, title, description, proposed_action, impact, created_at, status)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            """,
            (
                item.id,
                item.title,
                item.description,
                item.proposed_action,
                item.impact,
                item.created_at.isoformat(),
                item.status,
            ),
        )
        conn.commit()
    return item


def list_pending(db_path: Path = _DEFAULT_DB) -> list[ApprovalItem]:
    """Return all pending approval items, newest first."""
    with _get_conn(db_path) as conn:
        rows = conn.execute(
            "SELECT * FROM approval_items WHERE status = 'pending' ORDER BY created_at DESC"
        ).fetchall()
    return [_row_to_item(r) for r in rows]


def list_all(db_path: Path = _DEFAULT_DB) -> list[ApprovalItem]:
    """Return all approval items regardless of status, newest first."""
    with _get_conn(db_path) as conn:
        rows = conn.execute("SELECT * FROM approval_items ORDER BY created_at DESC").fetchall()
    return [_row_to_item(r) for r in rows]


def get_item(item_id: str, db_path: Path = _DEFAULT_DB) -> ApprovalItem | None:
    with _get_conn(db_path) as conn:
        row = conn.execute("SELECT * FROM approval_items WHERE id = ?", (item_id,)).fetchone()
    return _row_to_item(row) if row else None


def approve(item_id: str, db_path: Path = _DEFAULT_DB) -> ApprovalItem | None:
    """Mark an approval item as approved."""
    with _get_conn(db_path) as conn:
        conn.execute("UPDATE approval_items SET status = 'approved' WHERE id = ?", (item_id,))
        conn.commit()
    return get_item(item_id, db_path)


def reject(item_id: str, db_path: Path = _DEFAULT_DB) -> ApprovalItem | None:
    """Mark an approval item as rejected."""
    with _get_conn(db_path) as conn:
        conn.execute("UPDATE approval_items SET status = 'rejected' WHERE id = ?", (item_id,))
        conn.commit()
    return get_item(item_id, db_path)


def expire_old(db_path: Path = _DEFAULT_DB) -> int:
    """Auto-expire pending items older than EXPIRY_DAYS. Returns count removed."""
    cutoff = (datetime.now(UTC) - timedelta(days=_EXPIRY_DAYS)).isoformat()
    with _get_conn(db_path) as conn:
        cursor = conn.execute(
            "DELETE FROM approval_items WHERE status = 'pending' AND created_at < ?",
            (cutoff,),
        )
        conn.commit()
        count = cursor.rowcount
    return count
