#!/usr/bin/env python3
"""
TITAN MEMORY BLACK-BOX TEST SUITE
=================================
Tests external behavior without knowledge of internals.

Run: python -m pytest tests/test_titan_blackbox.py -v
"""

import os
import sys
import time
import unittest
from pathlib import Path
from unittest.mock import patch, MagicMock

# Add project root
sys.path.insert(0, str(Path(__file__).parent.parent))

# Set API key for tests
os.environ.setdefault('GEMINI_API_KEY', 'AIzaSyCT_rx0NusUJWoqtT7uxHAKEfHo129SJb8')


class TestFileScannerBlackBox(unittest.TestCase):
    """Black-box tests for file scanning functionality."""

    def test_scanner_returns_list(self):
        """T1: Scanner returns a list of files."""
        from core.titan.file_scanner import FileScanner

        scanner = FileScanner()
        files = scanner.scan()

        self.assertIsInstance(files, list)
        self.assertGreater(len(files), 0, "Should find at least some files")

    def test_scanner_returns_python_files_only(self):
        """T1b: Scanner returns only .py files."""
        from core.titan.file_scanner import FileScanner

        scanner = FileScanner()
        files = scanner.scan()

        for f in files:
            self.assertTrue(str(f).endswith('.py'), f"Non-Python file found: {f}")

    def test_scanner_respects_target_directories(self):
        """T1c: Scanner only scans specified directories."""
        from core.titan.file_scanner import FileScanner

        scanner = FileScanner(directories=['core'])
        files = scanner.scan()

        for f in files:
            self.assertIn('core', str(f), f"File outside core/: {f}")

    def test_scanner_file_count_reasonable(self):
        """T1d: Scanner returns reasonable file count for full stack."""
        from core.titan.file_scanner import FileScanner

        scanner = FileScanner()  # Default: core, skills, tools, rlm, swarms
        files = scanner.scan()

        # Should be between 100 and 1000 files
        self.assertGreater(len(files), 100, "Too few files found")
        self.assertLess(len(files), 1000, "Too many files found")


class TestCacheCreatorBlackBox(unittest.TestCase):
    """Black-box tests for cache creation."""

    def test_cache_creation_returns_object(self):
        """T2: Cache creation returns a TitanMemory object."""
        from core.titan.cache_manager import TitanCacheManager

        manager = TitanCacheManager()

        # Use minimal files for speed
        test_files = [Path(__file__)]

        # This makes a real API call
        result = manager.create_cache(
            files=test_files,
            display_name=f"test_blackbox_{int(time.time())}",
            ttl_minutes=5
        )

        self.assertIsNotNone(result, "Cache creation should return object")
        self.assertTrue(hasattr(result, 'name'), "Result should have 'name' attribute")
        self.assertTrue(hasattr(result, 'token_count'), "Result should have 'token_count'")

        # Cleanup
        if result:
            manager.delete_cache(result.name)

    def test_cache_appears_in_list(self):
        """T2b: Created cache appears in cache list."""
        from core.titan.cache_manager import TitanCacheManager

        manager = TitanCacheManager()
        test_files = [Path(__file__)]

        cache = manager.create_cache(
            files=test_files,
            display_name=f"test_list_{int(time.time())}",
            ttl_minutes=5
        )

        if cache:
            caches = manager.list_caches()
            cache_names = [c.name for c in caches]
            self.assertIn(cache.name, cache_names, "Cache should appear in list")

            # Cleanup
            manager.delete_cache(cache.name)


class TestQueryBlackBox(unittest.TestCase):
    """Black-box tests for query functionality."""

    def test_query_returns_response(self):
        """T3: Query with cache returns a response."""
        from core.titan.cache_manager import TitanCacheManager

        manager = TitanCacheManager()

        # Create a cache with known content
        test_file = Path("/tmp/titan_test_query.py")
        test_file.write_text('''
# SECRET_CODE = "GENESIS_TITAN_ALPHA"
def get_secret():
    return "GENESIS_TITAN_ALPHA"
''' + "# padding " * 1000)  # Pad for minimum token count

        try:
            cache = manager.create_cache(
                files=[test_file],
                display_name=f"test_query_{int(time.time())}",
                ttl_minutes=5
            )

            if cache:
                response = manager.query(
                    "What is the SECRET_CODE value in the Python file?",
                    cache_name=cache.name
                )

                self.assertIsNotNone(response, "Query should return response")
                self.assertIn("GENESIS_TITAN_ALPHA", response,
                             "Response should contain the secret code")

                # Cleanup
                manager.delete_cache(cache.name)
        finally:
            if test_file.exists():
                test_file.unlink()


class TestAutoRefreshBlackBox(unittest.TestCase):
    """Black-box tests for auto-refresh daemon."""

    def test_daemon_starts_and_stops(self):
        """T5: Daemon can be started and stopped."""
        from core.titan.refresh_daemon import TitanRefreshDaemon
        from core.titan.cache_manager import TitanCacheManager

        manager = TitanCacheManager()
        daemon = TitanRefreshDaemon(manager, check_interval=1)

        # Start daemon
        daemon.start()
        self.assertTrue(daemon.is_running(), "Daemon should be running after start")

        # Stop daemon
        daemon.stop()
        time.sleep(0.5)  # Give it time to stop
        self.assertFalse(daemon.is_running(), "Daemon should be stopped after stop")


class TestSystemRecoveryBlackBox(unittest.TestCase):
    """Black-box tests for failure recovery."""

    def test_handles_invalid_cache_name_gracefully(self):
        """T6: System handles invalid cache name gracefully."""
        from core.titan.cache_manager import TitanCacheManager

        manager = TitanCacheManager()

        # Query with non-existent cache should not crash
        result = manager.query(
            "test query",
            cache_name="cachedContents/nonexistent_12345"
        )

        # Should return None or error message, not crash
        self.assertTrue(result is None or isinstance(result, str))


if __name__ == '__main__':
    # Run with verbosity
    unittest.main(verbosity=2)
