"""SQLite-backed result cache."""

from __future__ import annotations

import hashlib
import json
import sqlite3
import tempfile
from pathlib import Path

from ai_qa.core.result import CheckResult


class Cache:
    """SQLite-backed cache for check results.

    Caches CheckResults to avoid re-running expensive LLM checks.
    Cache key is hash of context + check name + check version + prompt hash.
    """

    def __init__(self, db_path: str | Path | None = None) -> None:
        """Initialize cache.

        Args:
            db_path: Path to SQLite database. If None, uses temp DB.
        """
        if db_path is None:
            # Use temporary file database
            temp_dir = Path(tempfile.gettempdir()) / "ai_qa_cache"
            temp_dir.mkdir(parents=True, exist_ok=True)
            self.db_path = str(temp_dir / "cache.db")
        else:
            self.db_path = str(db_path)
            Path(self.db_path).parent.mkdir(parents=True, exist_ok=True)

        self._init_db()

    def _init_db(self) -> None:
        """Initialize database schema."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute(
                """
                CREATE TABLE IF NOT EXISTS cache (
                    key TEXT PRIMARY KEY,
                    check_result TEXT NOT NULL,
                    timestamp REAL
                )
                """
            )
            conn.commit()

    @staticmethod
    def _make_key(
        context_hash: str,
        check_name: str,
        check_version: str,
    ) -> str:
        """Create cache key from components.

        Args:
            context_hash: Hash of context.
            check_name: Check name.
            check_version: Check version.

        Returns:
            Cache key string.
        """
        key_str = f"{context_hash}::{check_name}::{check_version}"
        return hashlib.sha256(key_str.encode()).hexdigest()

    def get(
        self,
        context_hash: str,
        check_name: str,
        check_version: str,
    ) -> CheckResult | None:
        """Get cached result.

        Args:
            context_hash: Hash of context.
            check_name: Check name.
            check_version: Check version.

        Returns:
            CheckResult if cached, None otherwise.
        """
        key = self._make_key(context_hash, check_name, check_version)
        with sqlite3.connect(self.db_path) as conn:
            cursor = conn.execute("SELECT check_result FROM cache WHERE key = ?", (key,))
            row = cursor.fetchone()
            if row:
                result_dict = json.loads(row[0])
                return CheckResult(**result_dict)
            return None

    def put(
        self,
        context_hash: str,
        check_name: str,
        check_version: str,
        result: CheckResult,
    ) -> None:
        """Store result in cache.

        Args:
            context_hash: Hash of context.
            check_name: Check name.
            check_version: Check version.
            result: CheckResult to cache.
        """
        key = self._make_key(context_hash, check_name, check_version)
        result_json = json.dumps(result.model_dump())
        with sqlite3.connect(self.db_path) as conn:
            conn.execute(
                "INSERT OR REPLACE INTO cache (key, check_result, timestamp) VALUES (?, ?, ?)",
                (key, result_json, None),
            )
            conn.commit()

    def clear(self) -> None:
        """Clear all cached results."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute("DELETE FROM cache")
            conn.commit()
