"""Tests for SQL Loader."""

import pytest
from pathlib import Path
from unittest.mock import patch, MagicMock

from mes_dashboard.sql.loader import SQLLoader


class TestSQLLoader:
    """Test SQLLoader class."""

    def setup_method(self):
        """Clear cache before each test."""
        SQLLoader.clear_cache()

    def test_load_existing_file(self, tmp_path):
        """Test loading an existing SQL file."""
        # Create a temporary SQL file
        sql_dir = tmp_path / "wip"
        sql_dir.mkdir()
        sql_file = sql_dir / "summary.sql"
        sql_file.write_text("SELECT * FROM DWH.DW_MES_LOT_V")

        # Patch the _sql_dir to use our temp directory
        with patch.object(SQLLoader, "_sql_dir", tmp_path):
            result = SQLLoader.load("wip/summary")
            assert result == "SELECT * FROM DWH.DW_MES_LOT_V"

    def test_load_nonexistent_file(self):
        """Test loading a non-existent SQL file raises FileNotFoundError."""
        with pytest.raises(FileNotFoundError) as exc_info:
            SQLLoader.load("nonexistent/query")
        assert "SQL file not found" in str(exc_info.value)

    def test_load_uses_cache(self, tmp_path):
        """Test that repeated loads use the cache."""
        # Create a temporary SQL file
        sql_dir = tmp_path / "test"
        sql_dir.mkdir()
        sql_file = sql_dir / "cached.sql"
        sql_file.write_text("SELECT 1")

        with patch.object(SQLLoader, "_sql_dir", tmp_path):
            SQLLoader.clear_cache()

            # First load
            result1 = SQLLoader.load("test/cached")
            info1 = SQLLoader.cache_info()

            # Second load (should hit cache)
            result2 = SQLLoader.load("test/cached")
            info2 = SQLLoader.cache_info()

            assert result1 == result2
            assert info1.misses == 1
            assert info2.hits == 1

    def test_load_with_params_substitutes_values(self, tmp_path):
        """Test structural parameter substitution."""
        sql_dir = tmp_path
        sql_file = sql_dir / "query.sql"
        sql_file.write_text("SELECT * FROM {{ table_name }}")

        with patch.object(SQLLoader, "_sql_dir", tmp_path):
            result = SQLLoader.load_with_params("query", table_name="DWH.MY_TABLE")
            assert result == "SELECT * FROM DWH.MY_TABLE"

    def test_load_with_params_preserves_unsubstituted(self, tmp_path):
        """Test that unsubstituted parameters remain unchanged."""
        sql_dir = tmp_path
        sql_file = sql_dir / "query.sql"
        sql_file.write_text("SELECT * FROM {{ table_name }} {{ WHERE_CLAUSE }}")

        with patch.object(SQLLoader, "_sql_dir", tmp_path):
            result = SQLLoader.load_with_params("query", table_name="T")
            assert result == "SELECT * FROM T {{ WHERE_CLAUSE }}"

    def test_clear_cache(self, tmp_path):
        """Test cache clearing."""
        sql_dir = tmp_path
        sql_file = sql_dir / "test.sql"
        sql_file.write_text("SELECT 1")

        with patch.object(SQLLoader, "_sql_dir", tmp_path):
            SQLLoader.load("test")
            info_before = SQLLoader.cache_info()
            assert info_before.currsize > 0

            SQLLoader.clear_cache()
            info_after = SQLLoader.cache_info()
            assert info_after.currsize == 0

    def test_cache_info(self, tmp_path):
        """Test cache_info returns valid statistics."""
        sql_dir = tmp_path
        sql_file = sql_dir / "test.sql"
        sql_file.write_text("SELECT 1")

        with patch.object(SQLLoader, "_sql_dir", tmp_path):
            SQLLoader.clear_cache()
            SQLLoader.load("test")
            info = SQLLoader.cache_info()

            assert hasattr(info, "hits")
            assert hasattr(info, "misses")
            assert hasattr(info, "maxsize")
            assert hasattr(info, "currsize")
            assert info.maxsize == 100
