"""Session tracking for GreyMatter.

Records when you worked, what you did, and what patterns were applied.
"""
from typing import Any

from .db import Database
from .ids import generate_session_id


class SessionManager:
    """Manages session lifecycle."""

    def __init__(self, db: Database):
        self.db = db

    def start(self, project: str | None = None) -> dict[str, Any]:
        """Start a new session.

        Args:
            project: Optional project name to associate with the session.

        Returns:
            The created session as a dict.
        """
        session_id = generate_session_id()
        self.db.execute(
            "INSERT INTO sessions (id, project) VALUES (?, ?)",
            (session_id, project),
        )
        return self.get(session_id)

    def get(self, session_id: str) -> dict[str, Any] | None:
        """Get a session by ID.

        Args:
            session_id: The session ID to look up.

        Returns:
            The session dict, or None if not found.
        """
        return self.db.execute_one("SELECT * FROM sessions WHERE id = ?", (session_id,))

    def end(self, session_id: str, summary: str | None = None) -> dict[str, Any] | None:
        """End a session, recording the end time and optional summary.

        Args:
            session_id: The session ID to end.
            summary: Optional summary of what was accomplished.

        Returns:
            The updated session dict, or None if session not found.
        """
        if self.get(session_id) is None:
            return None
        self.db.execute(
            "UPDATE sessions SET ended_at = datetime('now'), summary = ? WHERE id = ?",
            (summary, session_id),
        )
        return self.get(session_id)

    def get_current(self) -> dict[str, Any] | None:
        """Get the current active (unended) session.

        Returns:
            The most recently started session that has not been ended,
            or None if no active session exists.
        """
        return self.db.execute_one(
            "SELECT * FROM sessions WHERE ended_at IS NULL ORDER BY started_at DESC LIMIT 1"
        )

    def get_recent(self, limit: int = 10) -> list[dict[str, Any]]:
        """Get recent sessions, ordered by most recent first.

        Args:
            limit: Maximum number of sessions to return. Defaults to 10.

        Returns:
            List of session dicts.
        """
        return self.db.execute(
            "SELECT * FROM sessions ORDER BY started_at DESC LIMIT ?", (limit,)
        )

    def checkpoint(self, session_id: str, context_summary: str = "", open_items: str = "") -> dict[str, Any]:
        """Save a session checkpoint for recovery after compaction.

        Args:
            session_id: The session to checkpoint.
            context_summary: Summary of current context for recovery.
            open_items: JSON string of open work items/tasks.

        Returns:
            Dict with checkpoint_id, session_id, and checkpoint_at, or error dict.
        """
        import uuid
        from datetime import datetime, timezone

        current = self.get(session_id)
        if not current:
            return {"error": f"Session not found: {session_id}"}

        checkpoint_id = f"cp-{uuid.uuid4().hex[:8]}"
        now = datetime.now(timezone.utc).isoformat()

        self.db.execute(
            """INSERT INTO session_checkpoints
               (id, session_id, checkpoint_at, state, active_work_item_id,
                compaction_count, context_summary, open_items)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
            (checkpoint_id, session_id, now,
             current.get("state", "active"),
             current.get("active_work_item_id"),
             current.get("compaction_count", 0),
             context_summary, open_items)
        )

        # Update session checkpoint_at
        self.db.execute(
            "UPDATE sessions SET checkpoint_at = ? WHERE id = ?",
            (now, session_id)
        )

        return {"checkpoint_id": checkpoint_id, "session_id": session_id, "checkpoint_at": now}

    def get_latest_checkpoint(self, session_id: str) -> dict[str, Any] | None:
        """Get the most recent checkpoint for a session.

        Args:
            session_id: The session ID to look up checkpoints for.

        Returns:
            The most recent checkpoint dict, or None if no checkpoints exist.
        """
        return self.db.execute_one(
            """SELECT * FROM session_checkpoints
               WHERE session_id = ?
               ORDER BY checkpoint_at DESC LIMIT 1""",
            (session_id,)
        )

    def update_state(self, session_id: str, state: str, active_work_item_id: str | None = None) -> bool:
        """Update session state and optionally the active work item.

        Args:
            session_id: The session ID to update.
            state: New state value (e.g., 'active', 'compacting', 'recovering').
            active_work_item_id: Optional work item ID to set as active.

        Returns:
            True after updating.
        """
        params: list[str] = [state]
        set_clause = "state = ?"
        if active_work_item_id is not None:
            set_clause += ", active_work_item_id = ?"
            params.append(active_work_item_id)
        params.append(session_id)
        self.db.execute(
            f"UPDATE sessions SET {set_clause} WHERE id = ?",
            tuple(params)
        )
        return True

    def increment_compaction(self, session_id: str) -> int:
        """Increment compaction counter, returns new count.

        Args:
            session_id: The session ID to increment compaction for.

        Returns:
            The new compaction count.
        """
        self.db.execute(
            "UPDATE sessions SET compaction_count = COALESCE(compaction_count, 0) + 1 WHERE id = ?",
            (session_id,)
        )
        row = self.db.execute_one(
            "SELECT compaction_count FROM sessions WHERE id = ?",
            (session_id,)
        )
        return row["compaction_count"] if row else 0
