#!/usr/bin/env python3
"""
Test Suite - Plugin Marketplace System

Tests for:
1. Plugin marketplace registry and loading
2. Plugin skill generation and matching
3. Dispatcher integration with plugins
4. Knowledge graph exports
5. Plugin-aware task dispatch
"""

import json
import sys
import tempfile
from pathlib import Path
from typing import Dict, List, Any

# Add lib to path
sys.path.insert(0, str(Path(__file__).parent.parent / "lib"))

from plugin_marketplace import (
    PluginMarketplaceRegistry,
    PluginCapabilityMatcher,
    get_marketplace_registry
)
from plugin_skill_loader import (
    PluginSkillLoader,
    get_plugin_skill_loader
)
from dispatcher_plugin_integration import (
    DispatcherPluginBridge,
    PluginAwareTaskDispatcher
)
from plugin_kg_integration import (
    PluginKnowledgeGraphExporter,
    export_plugins_to_kg
)


class TestResults:
    def __init__(self):
        self.tests: List[Dict[str, Any]] = []
        self.passed = 0
        self.failed = 0

    def add_test(self, name: str, passed: bool, details: str = ""):
        status = "PASS" if passed else "FAIL"
        self.tests.append({
            'name': name,
            'status': status,
            'details': details
        })
        if passed:
            self.passed += 1
        else:
            self.failed += 1
        print(f"[{status}] {name}" + (f": {details}" if details else ""))

    def summary(self) -> str:
        return f"\nTest Summary: {self.passed} passed, {self.failed} failed out of {self.passed + self.failed}"


def test_plugin_registry() -> TestResults:
    """Test plugin marketplace registry"""
    results = TestResults()
    print("\n=== Testing Plugin Marketplace Registry ===\n")

    # Test 1: Registry initialization
    try:
        registry = get_marketplace_registry()
        results.add_test(
            "Registry initialization",
            len(registry.plugins) > 0,
            f"Loaded {len(registry.plugins)} plugins"
        )
    except Exception as e:
        results.add_test("Registry initialization", False, str(e))
        return results

    # Test 2: Plugin retrieval
    try:
        plugin = registry.get_plugin('code-simplifier')
        results.add_test(
            "Plugin retrieval",
            plugin is not None and plugin.name == 'Code Simplifier',
            f"Retrieved: {plugin.name if plugin else 'None'}"
        )
    except Exception as e:
        results.add_test("Plugin retrieval", False, str(e))

    # Test 3: List plugins by category
    try:
        code_analysis_plugins = registry.list_plugins('code-analysis')
        results.add_test(
            "Filter plugins by category",
            len(code_analysis_plugins) > 0,
            f"Found {len(code_analysis_plugins)} code-analysis plugins"
        )
    except Exception as e:
        results.add_test("Filter plugins by category", False, str(e))

    # Test 4: Find plugins for task
    try:
        task = "Review my code for security vulnerabilities"
        matches = registry.find_plugins_for_task(task, ['security', 'review', 'code'])
        results.add_test(
            "Find plugins for task",
            len(matches) > 0,
            f"Found {len(matches)} matching plugins"
        )
    except Exception as e:
        results.add_test("Find plugins for task", False, str(e))

    # Test 5: Export plugin data
    try:
        export_data = registry.export_for_knowledge_graph()
        results.add_test(
            "Export for knowledge graph",
            'plugins' in export_data and 'categories' in export_data,
            f"Exported {len(export_data.get('plugins', {}))} plugins"
        )
    except Exception as e:
        results.add_test("Export for knowledge graph", False, str(e))

    return results


def test_plugin_skills() -> TestResults:
    """Test plugin skill generation and matching"""
    results = TestResults()
    print("\n=== Testing Plugin Skill System ===\n")

    # Test 1: Skill loader initialization
    try:
        loader = get_plugin_skill_loader()
        results.add_test(
            "Skill loader initialization",
            loader is not None,
            "Initialized successfully"
        )
    except Exception as e:
        results.add_test("Skill loader initialization", False, str(e))
        return results

    # Test 2: Generate skills from plugins
    try:
        skills = loader.generate_skills_from_plugins()
        results.add_test(
            "Generate skills from plugins",
            len(skills) > 0,
            f"Generated {len(skills)} skills"
        )
    except Exception as e:
        results.add_test("Generate skills from plugins", False, str(e))

    # Test 3: List all skills
    try:
        all_skills = loader.list_skills()
        results.add_test(
            "List all skills",
            len(all_skills) > 0,
            f"Listed {len(all_skills)} skills"
        )
    except Exception as e:
        results.add_test("List all skills", False, str(e))

    # Test 4: Filter skills by category
    try:
        code_skills = loader.list_skills(category='code-analysis')
        results.add_test(
            "Filter skills by category",
            len(code_skills) > 0,
            f"Found {len(code_skills)} code-analysis skills"
        )
    except Exception as e:
        results.add_test("Filter skills by category", False, str(e))

    # Test 5: Find skills for task
    try:
        task = "Simplify and optimize this Python function"
        matched = loader.find_skills_for_task(task, min_relevance=0.3)
        results.add_test(
            "Find skills for task",
            len(matched) > 0,
            f"Found {len(matched)} matching skills"
        )
    except Exception as e:
        results.add_test("Find skills for task", False, str(e))

    # Test 6: Export for dispatcher
    try:
        dispatch_export = loader.export_for_dispatcher()
        results.add_test(
            "Export for dispatcher",
            'skill_count' in dispatch_export and dispatch_export['skill_count'] > 0,
            f"Exported {dispatch_export.get('skill_count', 0)} skills"
        )
    except Exception as e:
        results.add_test("Export for dispatcher", False, str(e))

    # Test 7: Export for knowledge graph
    try:
        kg_export = loader.export_for_knowledge_graph()
        results.add_test(
            "Export for knowledge graph",
            'total_skills' in kg_export and kg_export['total_skills'] > 0,
            f"Exported {kg_export.get('total_skills', 0)} skills"
        )
    except Exception as e:
        results.add_test("Export for knowledge graph", False, str(e))

    return results


def test_dispatcher_integration() -> TestResults:
    """Test dispatcher-plugin integration"""
    results = TestResults()
    print("\n=== Testing Dispatcher Integration ===\n")

    # Test 1: Bridge initialization
    try:
        bridge = DispatcherPluginBridge()
        results.add_test(
            "Bridge initialization",
            bridge is not None and len(bridge.skill_loader.skills) > 0,
            f"Loaded {len(bridge.skill_loader.skills)} skills"
        )
    except Exception as e:
        results.add_test("Bridge initialization", False, str(e))
        return results

    # Test 2: Enhance task context
    try:
        task = "Review this code for security issues and performance"
        context = bridge.enhance_task_context(task, "test-project", "job-123")
        results.add_test(
            "Enhance task context",
            'plugin_analysis' in context and 'matched_skills' in context['plugin_analysis'],
            f"Found {len(context['plugin_analysis'].get('matched_skills', []))} skills"
        )
    except Exception as e:
        results.add_test("Enhance task context", False, str(e))

    # Test 3: Generate recommendations
    try:
        task = "Simplify and refactor this code"
        context = bridge.enhance_task_context(task, "test-project", "job-456")
        recommendations = context.get('recommended_plugins', {})
        results.add_test(
            "Generate recommendations",
            'primary_skill' in recommendations,
            f"Primary skill: {recommendations.get('primary_skill', {}).get('name', 'None')}"
        )
    except Exception as e:
        results.add_test("Generate recommendations", False, str(e))

    # Test 4: Plugin-aware task dispatcher
    try:
        dispatcher = PluginAwareTaskDispatcher(bridge)
        dispatch_result = dispatcher.dispatch_with_plugin_context(
            "Review code quality",
            "test-project",
            "job-789"
        )
        results.add_test(
            "Plugin-aware dispatch",
            dispatch_result['plugin_enhanced'] and 'plugin_context' in dispatch_result,
            "Dispatch successful with plugin context"
        )
    except Exception as e:
        results.add_test("Plugin-aware dispatch", False, str(e))

    # Test 5: Get dispatch recommendations
    try:
        dispatcher = PluginAwareTaskDispatcher(bridge)
        dispatcher.dispatch_with_plugin_context(
            "Analyze code performance",
            "test-project",
            "job-999"
        )
        recommendations = dispatcher.get_dispatch_recommendations("job-999")
        results.add_test(
            "Get dispatch recommendations",
            recommendations is not None and 'primary_skill' in recommendations,
            "Retrieved recommendations successfully"
        )
    except Exception as e:
        results.add_test("Get dispatch recommendations", False, str(e))

    return results


def test_capability_matching() -> TestResults:
    """Test plugin capability matching"""
    results = TestResults()
    print("\n=== Testing Capability Matching ===\n")

    # Test 1: Matcher initialization
    try:
        registry = get_marketplace_registry()
        matcher = PluginCapabilityMatcher(registry)
        results.add_test(
            "Matcher initialization",
            matcher is not None,
            "Initialized successfully"
        )
    except Exception as e:
        results.add_test("Matcher initialization", False, str(e))
        return results

    # Test 2: Extract keywords
    try:
        task = "Find security vulnerabilities in this code"
        keywords = matcher.extract_task_keywords(task)
        results.add_test(
            "Extract keywords",
            len(keywords) > 0 and 'security' in keywords,
            f"Extracted keywords: {keywords}"
        )
    except Exception as e:
        results.add_test("Extract keywords", False, str(e))

    # Test 3: Match plugins to task
    try:
        task = "Review code for performance issues"
        matches = matcher.match_plugins(task, min_relevance=0.3)
        results.add_test(
            "Match plugins to task",
            len(matches) > 0,
            f"Matched {len(matches)} plugins"
        )
    except Exception as e:
        results.add_test("Match plugins to task", False, str(e))

    # Test 4: Relevance scoring
    try:
        task1 = "Review code for security"
        task2 = "Deploy application"
        matches1 = matcher.match_plugins(task1)
        matches2 = matcher.match_plugins(task2)
        results.add_test(
            "Relevance scoring",
            len(matches1) > 0 and (len(matches2) == 0 or len(matches1) >= len(matches2)),
            "Security task has more relevant plugins than deploy task"
        )
    except Exception as e:
        results.add_test("Relevance scoring", False, str(e))

    return results


def test_knowledge_graph_export() -> TestResults:
    """Test knowledge graph exports"""
    results = TestResults()
    print("\n=== Testing Knowledge Graph Export ===\n")

    # Test 1: Exporter initialization
    try:
        exporter = PluginKnowledgeGraphExporter()
        results.add_test(
            "Exporter initialization",
            exporter is not None,
            "Initialized successfully"
        )
    except Exception as e:
        results.add_test("Exporter initialization", False, str(e))
        return results

    # Test 2: Export plugins as entities
    try:
        entities = exporter.export_plugins_as_entities()
        results.add_test(
            "Export plugins as entities",
            'entities' in entities and len(entities['entities']) > 0,
            f"Exported {len(entities['entities'])} plugin entities"
        )
    except Exception as e:
        results.add_test("Export plugins as entities", False, str(e))

    # Test 3: Export skills as entities
    try:
        entities = exporter.export_plugin_skills_as_entities()
        results.add_test(
            "Export skills as entities",
            'entities' in entities and len(entities['entities']) > 0,
            f"Exported {len(entities['entities'])} skill entities"
        )
    except Exception as e:
        results.add_test("Export skills as entities", False, str(e))

    # Test 4: Export relationships
    try:
        relations = exporter.export_plugin_relationships()
        results.add_test(
            "Export relationships",
            'relations' in relations and len(relations['relations']) > 0,
            f"Exported {len(relations['relations'])} relationships"
        )
    except Exception as e:
        results.add_test("Export relationships", False, str(e))

    # Test 5: Complete export
    try:
        complete = exporter.export_for_shared_kg()
        results.add_test(
            "Complete KG export",
            'plugins' in complete and 'skills' in complete and 'categories' in complete,
            f"Plugins: {len(complete['plugins'])}, Skills: {len(complete['skills'])}"
        )
    except Exception as e:
        results.add_test("Complete KG export", False, str(e))

    # Test 6: Save exports
    try:
        with tempfile.TemporaryDirectory() as tmpdir:
            export_dir = Path(tmpdir)
            saved = exporter.save_exports()
            results.add_test(
                "Save exports to files",
                len(saved) >= 3,
                f"Saved {len(saved)} export files"
            )
    except Exception as e:
        results.add_test("Save exports to files", False, str(e))

    return results


def run_all_tests() -> None:
    """Run all test suites"""
    print("=" * 60)
    print("PLUGIN SYSTEM TEST SUITE")
    print("=" * 60)

    all_results = []

    # Run test suites
    all_results.append(test_plugin_registry())
    all_results.append(test_plugin_skills())
    all_results.append(test_capability_matching())
    all_results.append(test_dispatcher_integration())
    all_results.append(test_knowledge_graph_export())

    # Print overall summary
    print("\n" + "=" * 60)
    print("OVERALL TEST SUMMARY")
    print("=" * 60)

    total_passed = sum(r.passed for r in all_results)
    total_failed = sum(r.failed for r in all_results)
    total_tests = total_passed + total_failed

    print(f"\nTotal: {total_passed}/{total_tests} tests passed")

    if total_failed > 0:
        print(f"\n{total_failed} tests failed:")
        for result_set in all_results:
            for test in result_set.tests:
                if test['status'] == 'FAIL':
                    print(f"  - {test['name']}: {test['details']}")

    print("\n" + "=" * 60)
    exit_code = 0 if total_failed == 0 else 1
    print(f"Exit code: {exit_code}")
    sys.exit(exit_code)


if __name__ == '__main__':
    run_all_tests()
