#!/usr/bin/env python3
"""Smoke tests for Layer 4 CLI commands (explain, graph, repair)."""

import json
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path

# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))

from tools.factory import create_artifact, persist_artifact


class TestCLIExplainGraphRepair(unittest.TestCase):
    """Smoke tests for explain, graph, and repair CLI commands."""

    def test_explain_by_file_works(self):
        """Explain command with --file should describe the artifact."""
        
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create test artifact
            payload = {
                "title": "Explain Test",
                "context": "Testing explain command",
                "options_considered": ["A", "B"],
                "chosen_option": "A",
                "reasoning": "For testing",
                "constraints": [],
                "assumptions": [],
                "confidence": 0.9,
                "expected_outcome": "Success",
                "category": "test"
            }
            
            artifact = create_artifact("decision", payload)
            path = persist_artifact(artifact, Path(tmpdir))
            
            # Run explain command
            result = subprocess.run(
                [
                    sys.executable, "-m", "tools.cli",
                    "explain",
                    "--file", str(path)
                ],
                capture_output=True,
                text=True,
                cwd=Path(__file__).parent.parent
            )
            
            # Should succeed
            self.assertEqual(result.returncode, 0,
                           f"Explain failed:\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}")
            
            # Should contain key information
            self.assertIn("Artifact Explanation", result.stdout)
            self.assertIn("Primary ID", result.stdout)
            self.assertIn("Explain Test", result.stdout)
            self.assertIn(artifact["uuid"], result.stdout)

    def test_graph_command_outputs_counts(self):
        """Graph command should show statistics."""
        
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create multiple artifacts
            for i in range(3):
                payload = {
                    "title": f"Graph Test {i}",
                    "context": "Testing graph",
                    "options_considered": ["A"],
                    "chosen_option": "A",
                    "reasoning": "Test",
                    "constraints": [],
                    "assumptions": [],
                    "confidence": 1.0,
                    "expected_outcome": "Success",
                    "category": "test"
                }
                artifact = create_artifact("decision", payload)
                persist_artifact(artifact, Path(tmpdir))
            
            # Run graph command
            result = subprocess.run(
                [
                    sys.executable, "-m", "tools.cli",
                    "graph",
                    "--directory", tmpdir
                ],
                capture_output=True,
                text=True,
                cwd=Path(__file__).parent.parent
            )
            
            # Should succeed
            self.assertEqual(result.returncode, 0,
                           f"Graph failed:\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}")
            
            # Should show counts
            self.assertIn("Graph Analysis", result.stdout)
            self.assertIn("Total artifacts: 3", result.stdout)
            self.assertIn("Statistics", result.stdout)

    def test_repair_dry_run_returns_zero(self):
        """Repair --dry-run should return exit code 0."""
        
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create artifact with orphaned link
            payload = {
                "title": "Repair Test",
                "context": "Testing repair",
                "options_considered": ["A"],
                "chosen_option": "A",
                "reasoning": "Test",
                "constraints": [],
                "assumptions": [],
                "confidence": 1.0,
                "expected_outcome": "No change",
                "category": "test"
            }
            artifact = create_artifact("decision", payload)
            artifact["Context_Link"] = "urn:uuid:orphan-0000-0000-0000-000000000000"
            persist_artifact(artifact, Path(tmpdir))
            
            # Run repair --dry-run
            result = subprocess.run(
                [
                    sys.executable, "-m", "tools.cli",
                    "repair",
                    "--directory", tmpdir,
                    "--dry-run"
                ],
                capture_output=True,
                text=True,
                cwd=Path(__file__).parent.parent
            )
            
            # Should succeed
            self.assertEqual(result.returncode, 0,
                           f"Repair dry-run failed:\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}")
            
            # Should indicate dry-run
            self.assertIn("DRY RUN", result.stdout)
            self.assertIn("orphaned", result.stdout.lower())

    def test_repair_real_run_returns_zero(self):
        """Repair without dry-run should fix orphans and return 0."""
        
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create artifact with orphaned link
            payload = {
                "title": "Repair Real Test",
                "context": "Testing real repair",
                "options_considered": ["A"],
                "chosen_option": "A",
                "reasoning": "Test",
                "constraints": [],
                "assumptions": [],
                "confidence": 1.0,
                "expected_outcome": "Clean",
                "category": "test"
            }
            artifact = create_artifact("decision", payload)
            artifact["Context_Link"] = "urn:uuid:orphan2-0000-0000-0000-000000000000"
            path = persist_artifact(artifact, Path(tmpdir))
            
            # Verify orphan exists
            with open(path, 'r') as f:
                data_before = json.load(f)
            self.assertIn("Context_Link", data_before)
            
            # Run repair (without --dry-run)
            result = subprocess.run(
                [
                    sys.executable, "-m", "tools.cli",
                    "repair",
                    "--directory", tmpdir
                ],
                capture_output=True,
                text=True,
                cwd=Path(__file__).parent.parent
            )
            
            # Should succeed
            self.assertEqual(result.returncode, 0,
                           f"Repair failed:\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}")
            
            # Should indicate removal
            self.assertTrue("removed" in result.stdout.lower() or "cleaned" in result.stdout.lower(),
                          f"Expected 'removed' or 'cleaned' in output: {result.stdout}")
            
            # Verify orphan was removed
            with open(path, 'r') as f:
                data_after = json.load(f)
            self.assertNotIn("Context_Link", data_after, "Orphaned link should be removed")

    def test_repair_with_create_stubs(self):
        """Repair --create-stubs should create stub artifacts."""
        
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create artifact with orphaned link
            payload = {
                "title": "Stub Creation Test",
                "context": "Testing stub creation",
                "options_considered": ["A"],
                "chosen_option": "A",
                "reasoning": "Test",
                "constraints": [],
                "assumptions": [],
                "confidence": 1.0,
                "expected_outcome": "Stub created",
                "category": "test"
            }
            artifact = create_artifact("decision", payload)
            orphan_id = "urn:uuid:stub-test-0000-0000-000000000000"
            artifact["Context_Link"] = orphan_id
            persist_artifact(artifact, Path(tmpdir))
            
            # Run repair --create-stubs
            result = subprocess.run(
                [
                    sys.executable, "-m", "tools.cli",
                    "repair",
                    "--directory", tmpdir,
                    "--create-stubs"
                ],
                capture_output=True,
                text=True,
                cwd=Path(__file__).parent.parent
            )
            
            # Should succeed
            self.assertEqual(result.returncode, 0,
                           f"Repair with stubs failed:\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}")
            
            # Should indicate stub creation
            self.assertTrue("created" in result.stdout.lower() or "stub" in result.stdout.lower(),
                          f"Expected 'created' or 'stub' in output: {result.stdout}")
            
            # Verify stub directory was created
            stub_dir = Path(tmpdir) / "stubs"
            self.assertTrue(stub_dir.exists(), "Stub directory should be created")
            
            # Verify stub file exists
            stub_files = list(stub_dir.glob("*.jsonld"))
            self.assertGreater(len(stub_files), 0, "At least one stub should be created")


if __name__ == '__main__':
    unittest.main()
