"""Git snapshot database operations."""

from __future__ import annotations

import json
from datetime import datetime, timezone
from typing import Any

from coral.store.connection import DatabaseManager


class GitStore(DatabaseManager):
    """Git snapshot CRUD operations."""

    async def upsert_git_snapshot(
        self,
        agent_name: str,
        agent_type: str,
        working_directory: str,
        branch: str,
        commit_hash: str,
        commit_subject: str,
        commit_timestamp: str | None,
        session_id: str | None = None,
        remote_url: str | None = None,
    ) -> None:
        now = datetime.now(timezone.utc).isoformat()
        conn = await self._get_conn()
        await conn.execute(
            """INSERT OR IGNORE INTO git_snapshots
               (agent_name, agent_type, working_directory, branch,
                commit_hash, commit_subject, commit_timestamp,
                session_id, remote_url, recorded_at)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
            (agent_name, agent_type, working_directory, branch,
             commit_hash, commit_subject, commit_timestamp,
             session_id, remote_url, now),
        )
        # Always update branch/working_directory on the latest row for this session
        update_params: list = [branch, working_directory, now]
        update_set = "branch = ?, working_directory = ?, recorded_at = ?"
        if remote_url is not None:
            update_set += ", remote_url = ?"
            update_params.append(remote_url)
        update_params.extend([session_id, commit_hash])
        await conn.execute(
            f"""UPDATE git_snapshots
               SET {update_set}
               WHERE session_id = ? AND commit_hash = ?""",
            update_params,
        )
        await conn.commit()

    async def get_git_snapshots(self, agent_name: str, limit: int = 20) -> list[dict[str, Any]]:
        conn = await self._get_conn()
        rows = await (await conn.execute(
            """SELECT agent_name, agent_type, working_directory, branch,
                      commit_hash, commit_subject, commit_timestamp,
                      session_id, remote_url, recorded_at
               FROM git_snapshots
               WHERE agent_name = ?
               ORDER BY recorded_at DESC
               LIMIT ?""",
            (agent_name, limit),
        )).fetchall()
        return [dict(r) for r in rows]

    async def get_latest_git_state(self, agent_name: str) -> dict[str, Any] | None:
        conn = await self._get_conn()
        row = await (await conn.execute(
            """SELECT agent_name, agent_type, working_directory, branch,
                      commit_hash, commit_subject, commit_timestamp,
                      session_id, remote_url, recorded_at
               FROM git_snapshots
               WHERE agent_name = ?
               ORDER BY recorded_at DESC
               LIMIT 1""",
            (agent_name,),
        )).fetchone()
        return dict(row) if row else None

    async def get_latest_git_state_by_session(self, session_id: str) -> dict[str, Any] | None:
        """Return the latest git snapshot for a specific session_id."""
        conn = await self._get_conn()
        row = await (await conn.execute(
            """SELECT agent_name, agent_type, working_directory, branch,
                      commit_hash, commit_subject, commit_timestamp,
                      session_id, remote_url, recorded_at
               FROM git_snapshots
               WHERE session_id = ?
               ORDER BY recorded_at DESC
               LIMIT 1""",
            (session_id,),
        )).fetchone()
        return dict(row) if row else None

    async def get_all_latest_git_state(self) -> dict[str, dict[str, Any]]:
        """Return {key: {branch, commit_hash, ...}} for all agents.

        Keyed by session_id when available, falling back to agent_name.
        """
        conn = await self._get_conn()
        rows = await (await conn.execute(
            """SELECT g.*
               FROM git_snapshots g
               INNER JOIN (
                   SELECT COALESCE(session_id, agent_name) AS grp_key,
                          MAX(recorded_at) as max_ts
                   FROM git_snapshots
                   GROUP BY grp_key
               ) latest ON COALESCE(g.session_id, g.agent_name) = latest.grp_key
                          AND g.recorded_at = latest.max_ts"""
        )).fetchall()
        result: dict[str, dict[str, Any]] = {}
        for r in rows:
            d = dict(r)
            # Key by session_id (for live sessions) AND agent_name (for legacy lookups)
            if r["session_id"]:
                result[r["session_id"]] = d
            result[r["agent_name"]] = d
        return result

    async def get_git_snapshots_for_session(self, session_id: str, limit: int = 100) -> list[dict[str, Any]]:
        """Return git commits linked to a session by session_id or by time range."""
        conn = await self._get_conn()
        rows = await (await conn.execute(
            """SELECT agent_name, agent_type, working_directory, branch,
                      commit_hash, commit_subject, commit_timestamp,
                      session_id, remote_url, recorded_at
               FROM git_snapshots
               WHERE session_id = ?
               ORDER BY commit_timestamp ASC
               LIMIT ?""",
            (session_id, limit),
        )).fetchall()
        if rows:
            return [dict(r) for r in rows]

        # Fallback: match by time range from session_index
        row = await (await conn.execute(
            "SELECT first_timestamp, last_timestamp FROM session_index WHERE session_id = ?",
            (session_id,),
        )).fetchone()
        if not row or not row["first_timestamp"] or not row["last_timestamp"]:
            return []

        rows = await (await conn.execute(
            """SELECT agent_name, agent_type, working_directory, branch,
                      commit_hash, commit_subject, commit_timestamp,
                      session_id, remote_url, recorded_at
               FROM git_snapshots
               WHERE commit_timestamp >= ? AND commit_timestamp <= ?
               ORDER BY commit_timestamp ASC
               LIMIT ?""",
            (row["first_timestamp"], row["last_timestamp"], limit),
        )).fetchall()
        return [dict(r) for r in rows]

    # ── Changed Files ─────────────────────────────────────────────────────

    async def replace_changed_files(
        self,
        agent_name: str,
        working_directory: str,
        files: list[dict[str, Any]],
        session_id: str | None = None,
    ) -> None:
        """Replace all changed-file records for an agent with a fresh snapshot."""
        now = datetime.now(timezone.utc).isoformat()
        conn = await self._get_conn()

        # Delete old records for this agent
        if session_id:
            await conn.execute(
                "DELETE FROM git_changed_files WHERE session_id = ?",
                (session_id,),
            )
        else:
            await conn.execute(
                "DELETE FROM git_changed_files WHERE agent_name = ? AND session_id IS NULL",
                (agent_name,),
            )

        # Insert fresh records
        for f in files:
            await conn.execute(
                """INSERT INTO git_changed_files
                   (agent_name, session_id, working_directory, filepath,
                    additions, deletions, status, recorded_at)
                   VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
                (agent_name, session_id, working_directory,
                 f["filepath"], f.get("additions", 0), f.get("deletions", 0),
                 f.get("status", "M"), now),
            )
        await conn.commit()

    async def get_changed_files(
        self, agent_name: str, session_id: str | None = None,
    ) -> list[dict[str, Any]]:
        """Return current changed files for an agent/session."""
        conn = await self._get_conn()
        if session_id:
            rows = await (await conn.execute(
                """SELECT filepath, additions, deletions, status, recorded_at
                   FROM git_changed_files
                   WHERE session_id = ?
                   ORDER BY filepath""",
                (session_id,),
            )).fetchall()
        else:
            rows = await (await conn.execute(
                """SELECT filepath, additions, deletions, status, recorded_at
                   FROM git_changed_files
                   WHERE agent_name = ? AND session_id IS NULL
                   ORDER BY filepath""",
                (agent_name,),
            )).fetchall()
        return [dict(r) for r in rows]

    async def get_all_changed_file_counts(self) -> dict[str, int]:
        """Return {session_id_or_agent_name: file_count} for all agents."""
        conn = await self._get_conn()
        rows = await (await conn.execute(
            """SELECT COALESCE(session_id, agent_name) AS key,
                      COUNT(*) AS cnt
               FROM git_changed_files
               GROUP BY key"""
        )).fetchall()
        return {r["key"]: r["cnt"] for r in rows}
