"""
Tests for the Kite CLI tool (kite init, kite validate).
"""

import pytest
import os
import sys
import tempfile
import shutil
from unittest.mock import patch


# =============================================================================
# FIXTURES
# =============================================================================

VALID_SKILL_MD = """\
---
name: test_cli_skill
description: Test skill for CLI
safety:
  forbidden_patterns: ["rm -rf"]
---

## Tool: greet
Say hello.

### Parameters
- name (str, required): Name to greet

### Script
```python
result = f"Hello, {name}!"
```
"""

INVALID_SKILL_MD = """\
---
name: broken
---

## Tool: fail

### Script
```python
def this is not valid python !!!
```
"""


@pytest.fixture
def tmp_dir(tmp_path):
    """Provide a clean temp directory for each test."""
    return tmp_path


@pytest.fixture
def valid_skill_file(tmp_path):
    """Create a valid skill file."""
    skill_file = tmp_path / "valid_skill.md"
    skill_file.write_text(VALID_SKILL_MD)
    return str(skill_file)


@pytest.fixture
def invalid_skill_file(tmp_path):
    """Create an invalid skill file."""
    skill_file = tmp_path / "invalid_skill.md"
    skill_file.write_text(INVALID_SKILL_MD)
    return str(skill_file)


# =============================================================================
# CLI INIT TESTS
# =============================================================================

class TestCLIInit:
    """Test 'kite init' command."""
    
    def test_init_agent_project(self, tmp_dir):
        """Test scaffolding an agent project."""
        from kite.cli import cmd_init
        
        args = type('Args', (), {
            'name': 'test_agent',
            'type': 'agent',
            'from_md': None
        })()
        
        original_cwd = os.getcwd()
        try:
            os.chdir(str(tmp_dir))
            cmd_init(args)
            
            project_dir = tmp_dir / "test_agent"
            assert project_dir.exists()
            assert (project_dir / "main.py").exists()
            assert (project_dir / ".env.example").exists()
            assert (project_dir / "requirements.txt").exists()
            assert (project_dir / "skills" / "skill.md").exists()
            
            # Verify main.py is valid Python
            main_content = (project_dir / "main.py").read_text()
            compile(main_content, "main.py", "exec")
        finally:
            os.chdir(original_cwd)
    
    def test_init_workflow_project(self, tmp_dir):
        """Test scaffolding a workflow project."""
        from kite.cli import cmd_init
        
        args = type('Args', (), {
            'name': 'test_workflow',
            'type': 'workflow',
            'from_md': None
        })()
        
        original_cwd = os.getcwd()
        try:
            os.chdir(str(tmp_dir))
            cmd_init(args)
            
            project_dir = tmp_dir / "test_workflow"
            assert project_dir.exists()
            assert (project_dir / "main.py").exists()
            
            main_content = (project_dir / "main.py").read_text()
            assert "workflow" in main_content.lower() or "pipeline" in main_content.lower()
            compile(main_content, "main.py", "exec")
        finally:
            os.chdir(original_cwd)
    
    def test_init_tool_project(self, tmp_dir):
        """Test scaffolding a standalone tool project."""
        from kite.cli import cmd_init
        
        args = type('Args', (), {
            'name': 'my_tool',
            'type': 'tool',
            'from_md': None
        })()
        
        original_cwd = os.getcwd()
        try:
            os.chdir(str(tmp_dir))
            cmd_init(args)
            
            project_dir = tmp_dir / "my_tool"
            assert project_dir.exists()
            assert (project_dir / "main.py").exists()
            
            main_content = (project_dir / "main.py").read_text()
            assert "Tool" in main_content
            compile(main_content, "main.py", "exec")
        finally:
            os.chdir(original_cwd)
    
    def test_init_from_md(self, tmp_dir, valid_skill_file):
        """Test scaffolding from a skill.md file."""
        from kite.cli import cmd_init
        
        args = type('Args', (), {
            'name': 'from_md_agent',
            'type': 'agent',
            'from_md': valid_skill_file
        })()
        
        original_cwd = os.getcwd()
        try:
            os.chdir(str(tmp_dir))
            cmd_init(args)
            
            project_dir = tmp_dir / "from_md_agent"
            skill_file = project_dir / "skills" / "skill.md"
            assert skill_file.exists()
            
            # Verify the skill content was copied
            skill_content = skill_file.read_text()
            assert "test_cli_skill" in skill_content
            
            # Verify main.py references the skill
            main_content = (project_dir / "main.py").read_text()
            assert "create_agent_from_skill" in main_content
        finally:
            os.chdir(original_cwd)
    
    def test_init_existing_directory_fails(self, tmp_dir):
        """Test that init fails for existing directory."""
        from kite.cli import cmd_init
        
        # Create the directory first
        (tmp_dir / "existing").mkdir()
        
        args = type('Args', (), {
            'name': 'existing',
            'type': 'agent',
            'from_md': None
        })()
        
        original_cwd = os.getcwd()
        try:
            os.chdir(str(tmp_dir))
            with pytest.raises(SystemExit):
                cmd_init(args)
        finally:
            os.chdir(original_cwd)
    
    def test_init_from_invalid_md(self, tmp_dir, invalid_skill_file):
        """Test that init with invalid skill file fails."""
        from kite.cli import cmd_init
        
        args = type('Args', (), {
            'name': 'bad_agent',
            'type': 'agent',
            'from_md': invalid_skill_file
        })()
        
        original_cwd = os.getcwd()
        try:
            os.chdir(str(tmp_dir))
            with pytest.raises(SystemExit):
                cmd_init(args)
        finally:
            os.chdir(original_cwd)


# =============================================================================
# CLI VALIDATE TESTS
# =============================================================================

class TestCLIValidate:
    """Test 'kite validate' command."""
    
    def test_validate_valid_skill(self, valid_skill_file):
        """Test validating a valid skill file."""
        from kite.cli import cmd_validate
        
        args = type('Args', (), {'skill_file': valid_skill_file})()
        # Should not raise
        cmd_validate(args)
    
    def test_validate_invalid_skill(self, invalid_skill_file):
        """Test validating an invalid skill file."""
        from kite.cli import cmd_validate
        
        args = type('Args', (), {'skill_file': invalid_skill_file})()
        with pytest.raises(SystemExit):
            cmd_validate(args)
    
    def test_validate_nonexistent_file(self):
        """Test validating a nonexistent file."""
        from kite.cli import cmd_validate
        
        args = type('Args', (), {'skill_file': '/nonexistent/skill.md'})()
        with pytest.raises(SystemExit):
            cmd_validate(args)


# =============================================================================
# CLI MAIN ENTRY POINT TESTS
# =============================================================================

class TestCLIMain:
    """Test CLI main entry point parsing."""
    
    def test_main_no_args(self):
        """Test calling main with no args."""
        from kite.cli import main
        
        with patch('sys.argv', ['kite']):
            with pytest.raises(SystemExit):
                main()
    
    def test_main_help(self):
        """Test calling main with --help."""
        from kite.cli import main
        
        with patch('sys.argv', ['kite', '--help']):
            with pytest.raises(SystemExit) as exc_info:
                main()
            assert exc_info.value.code == 0


# =============================================================================
# TEMPLATE GENERATION TESTS
# =============================================================================

class TestTemplates:
    """Test template content generation."""
    
    def test_agent_template_valid_python(self):
        """Test that agent template generates valid Python."""
        from kite.cli import _generate_agent_main
        code = _generate_agent_main("test_agent")
        compile(code, "main.py", "exec")
    
    def test_agent_from_md_template_valid_python(self):
        """Test that agent-from-md template generates valid Python."""
        from kite.cli import _generate_agent_main
        code = _generate_agent_main("test_agent", "skill.md")
        compile(code, "main.py", "exec")
        assert "create_agent_from_skill" in code
    
    def test_workflow_template_valid_python(self):
        """Test that workflow template generates valid Python."""
        from kite.cli import _generate_workflow_main
        code = _generate_workflow_main("test_workflow")
        compile(code, "main.py", "exec")
    
    def test_workflow_from_md_template_valid_python(self):
        """Test that workflow-from-md template generates valid Python."""
        from kite.cli import _generate_workflow_main
        code = _generate_workflow_main("test_workflow", "skill.md")
        compile(code, "main.py", "exec")
        assert "load_skill" in code
    
    def test_tool_template_valid_python(self):
        """Test that tool template generates valid Python."""
        from kite.cli import _generate_tool_main
        code = _generate_tool_main("my_tool")
        compile(code, "main.py", "exec")


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
