"""
Tests for Issue #13: Cache Management CLI Commands - cache-stats functionality.

This module tests the cache-stats command which displays cache statistics and effectiveness.
The cache-stats command should provide detailed metrics including hit rate, memory usage,
file count, and performance monitoring data.
"""

import json
import os
import tempfile
from pathlib import Path
from unittest.mock import patch, MagicMock

import pytest
from click.testing import CliRunner

from markitect.cli import cli
from markitect.ast_cache import ASTCache
from markitect.database import DatabaseManager


class TestCacheStatsCommand:
    """Test suite for cache-stats command functionality."""

    def setup_method(self):
        """Set up test environment for each test."""
        self.runner = CliRunner()
        self.temp_dir = tempfile.mkdtemp()
        self.cache_dir = Path(self.temp_dir) / ".ast_cache"
        self.db_path = Path(self.temp_dir) / "test.db"

        # Create test markdown file
        self.test_file = Path(self.temp_dir) / "test.md"
        self.test_file.write_text("""---
title: Test Document
author: Test Author
---

# Test Heading

This is a test document with some content.

## Section 1

Content for section 1.

## Section 2

More content here.
""")

    def teardown_method(self):
        """Clean up after each test."""
        import shutil
        if Path(self.temp_dir).exists():
            shutil.rmtree(self.temp_dir)

    def test_cache_info_command_exists(self):
        """Test that cache-stats command is available in CLI."""
        # This test will initially fail until command is implemented
        result = self.runner.invoke(cli, ['cache-stats'])

        # Should not return "No such command" error
        assert "No such command" not in result.output
        assert result.exit_code in [0, 1]  # 0 for success, 1 for expected errors

    def test_cache_info_displays_basic_statistics(self):
        """Test that cache-stats displays basic cache statistics."""
        # Setup: Create cache with some files
        cache = ASTCache(self.cache_dir)
        cache.cache_file(self.test_file)

        # Execute command - patch the cache service instead of global Path
        with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
            mock_cache_dir.return_value = self.cache_dir
            result = self.runner.invoke(cli, ['cache-stats'])

        # Should show cache statistics
        assert result.exit_code == 0
        assert "Cache Directory:" in result.output
        assert "Total Files:" in result.output
        assert "Cache Size:" in result.output

    def test_cache_info_shows_file_count(self):
        """Test that cache-stats correctly reports number of cached files."""
        # Setup: Create multiple cached files
        cache = ASTCache(self.cache_dir)

        # Create additional test files
        test_file2 = Path(self.temp_dir) / "test2.md"
        test_file2.write_text("# Another Test\n\nContent here.")

        cache.cache_file(self.test_file)
        cache.cache_file(test_file2)

        # Execute command - mock CacheDirectoryService to return our test cache stats
        with patch('markitect.cli.CacheDirectoryService') as mock_cache_service:
            mock_service_instance = MagicMock()
            mock_service_instance.get_cache_stats.return_value = {
                'directory': str(self.cache_dir),
                'total_files': 2,
                'size_formatted': '1.2 KB'
            }
            mock_cache_service.return_value = mock_service_instance
            result = self.runner.invoke(cli, ['cache-stats'])

        assert result.exit_code == 0
        assert "Total Files: 2" in result.output

    def test_cache_info_shows_memory_usage(self):
        """Test that cache-stats displays memory usage information."""
        # Setup: Create cache with content
        cache = ASTCache(self.cache_dir)
        cache.cache_file(self.test_file)

        # Execute command - patch the cache service instead of global Path
        with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
            mock_cache_dir.return_value = self.cache_dir
            result = self.runner.invoke(cli, ['cache-stats'])

        assert result.exit_code == 0
        # Should show memory/size information
        assert any(keyword in result.output.lower() for keyword in ["size", "memory", "bytes", "kb", "mb"])

    def test_cache_info_with_empty_cache(self):
        """Test cache-stats behavior with empty cache directory."""
        # Ensure cache directory exists but is empty
        self.cache_dir.mkdir(exist_ok=True)

        # Clear any existing files to ensure it's actually empty
        for file in self.cache_dir.iterdir():
            if file.is_file():
                file.unlink()

        # Execute command - patch the cache stats directly for this test
        with patch('markitect.cache_service.CacheDirectoryService.get_cache_stats') as mock_stats:
            mock_stats.return_value = {
                'directory': str(self.cache_dir),
                'total_files': 0,
                'size_formatted': '0 B'
            }
            result = self.runner.invoke(cli, ['cache-stats'])

        assert result.exit_code == 0
        assert "Total Files: 0" in result.output or "empty" in result.output.lower()

    def test_cache_info_with_nonexistent_cache(self):
        """Test cache-stats behavior when cache directory doesn't exist."""
        # Use non-existent cache directory
        nonexistent_dir = Path(self.temp_dir) / "nonexistent_cache"

        # Execute command - patch the cache service instead of global Path
        with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
            mock_cache_dir.return_value = nonexistent_dir
            result = self.runner.invoke(cli, ['cache-stats'])

        # Should handle gracefully, either create directory or show appropriate message
        assert result.exit_code in [0, 1]
        assert "error" in result.output.lower() or "not found" in result.output.lower() or "0" in result.output

    def test_cache_info_output_format(self):
        """Test that cache-stats output is well-formatted and readable."""
        # Setup: Create cache with content
        cache = ASTCache(self.cache_dir)
        cache.cache_file(self.test_file)

        # Execute command - patch the cache service instead of global Path
        with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
            mock_cache_dir.return_value = self.cache_dir
            result = self.runner.invoke(cli, ['cache-stats'])

        assert result.exit_code == 0

        # Should have structured output with clear labels
        lines = result.output.strip().split('\n')
        assert len(lines) >= 3  # Should have multiple lines of info

        # Should contain key information
        output_lower = result.output.lower()
        assert "cache" in output_lower
        assert any(char in result.output for char in [':'])  # Should have label:value format

    def test_cache_info_performance_metrics(self):
        """Test that cache-stats includes performance-related metrics."""
        # Setup: Create cache and simulate usage
        cache = ASTCache(self.cache_dir)
        cache.cache_file(self.test_file)

        # Load cached AST to simulate cache hit
        cache.load_cached_ast(self.test_file)

        # Execute command - patch the cache service instead of global Path
        with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
            mock_cache_dir.return_value = self.cache_dir
            result = self.runner.invoke(cli, ['cache-stats'])

        assert result.exit_code == 0
        # Should include performance-related information
        # This might include cache effectiveness, file ages, etc.
        assert len(result.output.strip()) > 50  # Should be substantial output

    def test_cache_info_with_verbose_flag(self):
        """Test cache-stats with verbose flag showing detailed information."""
        # Setup: Create cache with content
        cache = ASTCache(self.cache_dir)
        cache.cache_file(self.test_file)

        # Execute command with verbose flag - patch the cache service instead of global Path
        with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
            mock_cache_dir.return_value = self.cache_dir
            result = self.runner.invoke(cli, ['--verbose', 'cache-stats'])

        # Verbose mode might show more detailed information
        # For now, just ensure command works
        assert result.exit_code in [0, 1]