"""Caching system for GuardRail."""

import hashlib
import sqlite3
from pathlib import Path
from typing import Optional


class Cache:
    """Simple cache for function hashes and test files."""

    def __init__(self, cache_file: Path):
        """
        Initialize cache.

        Args:
            cache_file: Path to SQLite cache file.
        """
        self.cache_file = Path(cache_file)
        self._ensure_db()

    def _ensure_db(self) -> None:
        """Ensure cache database exists with proper schema."""
        self.cache_file.parent.mkdir(parents=True, exist_ok=True)
        
        conn = sqlite3.connect(str(self.cache_file))
        cursor = conn.cursor()
        
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS function_cache (
                function_key TEXT PRIMARY KEY,
                function_hash TEXT NOT NULL,
                test_file_path TEXT NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        
        conn.commit()
        conn.close()

    def compute_hash(self, function_source: str, file_path: Path, function_name: str) -> str:
        """
        Compute hash for a function.

        Args:
            function_source: Source code of the function.
            file_path: Path to the file containing the function.
            function_name: Name of the function.

        Returns:
            SHA256 hash of the function.
        """
        # Create a unique key for this function
        key = f"{file_path}:{function_name}"
        content = f"{key}\n{function_source}"
        return hashlib.sha256(content.encode()).hexdigest()

    def get_cached_test(self, function_source: str, file_path: Path, function_name: str) -> Optional[Path]:
        """
        Get cached test file path if function hash matches.

        Args:
            function_source: Source code of the function.
            file_path: Path to the file containing the function.
            function_name: Name of the function.

        Returns:
            Path to cached test file if found, None otherwise.
        """
        function_key = f"{file_path}:{function_name}"
        current_hash = self.compute_hash(function_source, file_path, function_name)
        
        conn = sqlite3.connect(str(self.cache_file))
        cursor = conn.cursor()
        
        cursor.execute("""
            SELECT test_file_path, function_hash
            FROM function_cache
            WHERE function_key = ?
        """, (function_key,))
        
        result = cursor.fetchone()
        conn.close()
        
        if result:
            cached_test_path, cached_hash = result
            if cached_hash == current_hash:
                # Hash matches, return cached test
                test_path = Path(cached_test_path)
                if test_path.exists():
                    return test_path
        
        return None

    def store_test(self, function_source: str, file_path: Path, function_name: str, test_file_path: Path) -> None:
        """
        Store test file path in cache.

        Args:
            function_source: Source code of the function.
            file_path: Path to the file containing the function.
            function_name: Name of the function.
            test_file_path: Path to the generated test file.
        """
        function_key = f"{file_path}:{function_name}"
        function_hash = self.compute_hash(function_source, file_path, function_name)
        
        conn = sqlite3.connect(str(self.cache_file))
        cursor = conn.cursor()
        
        cursor.execute("""
            INSERT OR REPLACE INTO function_cache
            (function_key, function_hash, test_file_path)
            VALUES (?, ?, ?)
        """, (function_key, function_hash, str(test_file_path)))
        
        conn.commit()
        conn.close()

