import unittest
import sys
import os
import json
import subprocess
import hashlib
from pathlib import Path

# Set up paths
PROJECT_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT_ROOT))


class SmokeTest(unittest.TestCase):
    """Original 6 smoke tests."""

    def test_import_brain_utils(self):
        """Test 1: import brain_utils succeeds"""
        from pulse.core import brain_utils

    def test_import_pulse_boot(self):
        """Test 2: import pulse_boot succeeds"""
        from pulse.brain import pulse_boot

    def test_brain_query_runs(self):
        """Test 3: brain_query.py runs with --query test without crash"""
        script_path = PROJECT_ROOT / "pulse" / "brain" / "brain_query.py"
        result = subprocess.run(
            [sys.executable, str(script_path), "--query", "test"],
            capture_output=True, text=True, timeout=30,
        )
        self.assertEqual(result.returncode, 0, f"brain_query.py crashed: {result.stderr}")

    def test_task_board_valid_json(self):
        """Test 4: task_board.json is valid JSON"""
        path = PROJECT_ROOT / "Prefrontal_Cortex" / "Action_Queue" / "task_board.json"
        if not path.exists():
            self.skipTest(f"{path} not found")
        with open(path, "r", encoding="utf-8") as f:
            json.load(f)

    def test_constitution_hash(self):
        """Test 5: CONSTITUTION.md hash matches .env CONSTITUTION_HASH"""
        env_path = PROJECT_ROOT / ".env"
        if not env_path.exists():
            self.skipTest(".env file missing")
        target_hash = None
        with open(env_path, "r", encoding="utf-8") as f:
            for line in f:
                if line.strip().startswith("CONSTITUTION_HASH="):
                    target_hash = line.split("=", 1)[1].strip().strip('"').strip("'")
                    break
        if not target_hash:
            self.skipTest("CONSTITUTION_HASH not found in .env")
        const_path = PROJECT_ROOT / "Corpus_Callosum" / "CONSTITUTION.md"
        if not const_path.exists():
            self.fail(f"CONSTITUTION.md not found at {const_path}")
        file_hash = hashlib.sha256(const_path.read_bytes()).hexdigest()
        self.assertEqual(file_hash, target_hash, "Constitution hash mismatch!")

    def test_agent_registry_valid_json(self):
        """Test 6: agent_registry.json is valid JSON"""
        path = PROJECT_ROOT / "state" / "agent_registry.json"
        if not path.exists():
            self.skipTest("agent_registry.json not found")
        with open(path, "r", encoding="utf-8") as f:
            json.load(f)


class ImportTests(unittest.TestCase):
    """Test 7-14: Import tests for all critical modules."""

    def test_import_brain_search(self):
        from pulse.brain import brain_search

    def test_import_save_writers(self):
        from pulse.brain.save_writers import append_knowledge_md

    def test_import_pulse_save(self):
        from pulse.brain.pulse_save import save

    def test_import_boot_briefing(self):
        from pulse.brain.boot_briefing import build_brain_briefing

    def test_import_wants_parser(self):
        from pulse.brain.wants_parser import parse_full

    def test_import_task_ops(self):
        from pulse.tasks.task_ops import detect_tier, claim_task

    def test_import_cli_status(self):
        from pulse.cli.status import cmd_status

    def test_import_cli_swarm(self):
        from pulse.cli.cmd_swarm import cmd_swarm


class FunctionalTests(unittest.TestCase):
    """Test 15-22: Functional tests for critical paths."""

    def test_brain_search_returns_results(self):
        """Test 15: brain_search returns results for known query"""
        from pulse.brain.brain_search import brain_search
        result = brain_search("architecture refactor")
        self.assertIsInstance(result, dict)
        self.assertIn("results", result)

    def test_brain_search_has_results(self):
        """Test 16: brain_search returns structured results"""
        from pulse.brain.brain_search import brain_search
        result = brain_search("windows encoding")
        self.assertIsInstance(result, dict)

    def test_pulse_save_dry_run(self):
        """Test 17: pulse_save.py runs without crash (no actual save)"""
        script_path = PROJECT_ROOT / "pulse" / "brain" / "pulse_save.py"
        result = subprocess.run(
            [sys.executable, str(script_path),
             "--agent", "test", "--learnings", "test learning sentence here",
             "--json"],
            capture_output=True, text=True, timeout=30,
        )
        self.assertEqual(result.returncode, 0, f"pulse_save crashed: {result.stderr}")
        output = json.loads(result.stdout)
        self.assertIn("learnings_saved", output)

    def test_detect_tier(self):
        """Test 18: tier detection works correctly"""
        from pulse.tasks.task_ops import detect_tier
        self.assertEqual(detect_tier("claude-opus"), "premium")
        self.assertEqual(detect_tier("claude-sonnet"), "standard")
        self.assertEqual(detect_tier("claude-haiku"), "fast")

    def test_import_retroactive_llm_extractor(self):
        """Test 19: retroactive_llm_extractor imports clean"""
        from pulse.admin.retroactive.retroactive_llm_extractor import batch_interactions, write_to_brain

    def test_prediction_metrics_exist(self):
        """Test 20: prediction_metrics.json exists and is valid"""
        path = PROJECT_ROOT / "state" / "prediction_metrics.json"
        if not path.exists():
            self.skipTest("prediction_metrics.json not found")
        data = json.loads(path.read_text(encoding="utf-8"))
        self.assertIn("total_predictions", data)
        self.assertIn("outcomes", data)

    def test_prediction_accuracy(self):
        """Test 21: get_prediction_accuracy returns valid dict"""
        from pulse.daemons.neural.prediction_feedback import get_prediction_accuracy
        acc = get_prediction_accuracy()
        self.assertIn("accuracy", acc)
        self.assertIn("total", acc)

    def test_brain_files_exist(self):
        """Test 22: brain knowledge files exist (skip on CI where brain isn't populated)"""
        lessons = PROJECT_ROOT / "Hippocampus" / "Lessons" / "auto_lessons.md"
        fails = PROJECT_ROOT / "Hippocampus" / "Failures" / "auto_fails.md"
        patterns = PROJECT_ROOT / "Hippocampus" / "Patterns" / "auto_patterns.md"
        if not lessons.exists():
            self.skipTest("Brain files not populated (CI environment)")
        self.assertTrue(fails.exists(), "auto_fails.md missing")
        self.assertTrue(patterns.exists(), "auto_patterns.md missing")


if __name__ == "__main__":
    unittest.main(verbosity=2)
