"""Integration tests for the full workflow."""

import os
import subprocess
from pathlib import Path
from unittest.mock import patch

import pytest


class TestFullWorkflow:
    """Test complete user workflows."""

    def test_init_and_run_workflow(self, scry_run_home):
        """Test creating and running an app."""
        # 1. Create app via subprocess
        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--name", "test-app", "--description", "Test"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0, f"init failed: {result.stderr}"

        # 2. Verify structure
        app_dir = scry_run_home / "apps" / "test-app"
        assert (app_dir / "app.py").exists()
        assert (app_dir / "cache.json").exists()
        assert (app_dir / "logs").exists()

        # 3. Verify app.py is valid Python
        app_py = app_dir / "app.py"
        compile(app_py.read_text(), str(app_py), "exec")

    def test_env_command_output_is_sourceable(self, scry_run_home):
        """Test env command output is valid shell."""
        result = subprocess.run(
            ["uv", "run", "scry-run", "env"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )

        assert result.returncode == 0, f"env failed: {result.stderr}"

        # All non-empty lines should be valid exports
        for line in result.stdout.strip().split("\n"):
            if line:
                assert line.startswith("export ")

    def test_config_loading_in_run(self, scry_run_home):
        """Test run command loads and applies config."""
        # Create config
        config_path = scry_run_home / "config.toml"
        config_path.write_text("""
[defaults]
backend = "claude"

[backend.claude]
model = "opus"
""")

        # Build env without SCRY_BACKEND to test config file loading
        env = {k: v for k, v in os.environ.items() if k != "SCRY_BACKEND"}
        env["SCRY_HOME"] = str(scry_run_home)

        # Create app (with --no-auto-expand to avoid LLM calls)
        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--name", "config-test", "--description", "Test", "--no-auto-expand"],
            env=env,
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0

        # Verify env command shows config values
        result = subprocess.run(
            ["uv", "run", "scry-run", "env"],
            env=env,
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0
        assert 'SCRY_BACKEND="claude"' in result.stdout
        assert 'SCRY_MODEL="opus"' in result.stdout

    def test_cache_workflow(self, scry_run_home):
        """Test cache list/show commands work with apps."""
        # Create app
        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--name", "cache-test", "--description", "Test"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0

        # List apps (should show cache-test with 0 entries)
        result = subprocess.run(
            ["uv", "run", "scry-run", "cache", "list"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0
        assert "cache-test" in result.stdout


class TestCLIHelp:
    """Test that CLI help messages work correctly."""

    def test_main_help(self):
        """Test main --help works."""
        result = subprocess.run(
            ["uv", "run", "scry-run", "--help"],
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0
        assert "scry-run" in result.stdout
        assert "init" in result.stdout
        assert "env" in result.stdout
        assert "cache" in result.stdout

    def test_init_help(self):
        """Test init --help works."""
        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--help"],
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0
        assert "--name" in result.stdout
        assert "--description" in result.stdout

    def test_cache_help(self):
        """Test cache --help works."""
        result = subprocess.run(
            ["uv", "run", "scry-run", "cache", "--help"],
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0
        assert "list" in result.stdout
        assert "export" in result.stdout


class TestAppStructure:
    """Test that created apps have correct structure."""

    def test_app_py_has_shebang(self, scry_run_home):
        """Test app.py has proper shebang."""
        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--name", "shebang-test", "--description", "Test"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0

        app_py = scry_run_home / "apps" / "shebang-test" / "app.py"
        content = app_py.read_text()
        assert content.startswith("#!/usr/bin/env python3")

    def test_app_py_is_executable(self, scry_run_home):
        """Test app.py has executable permission."""
        import stat

        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--name", "exec-test", "--description", "Test"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0

        app_py = scry_run_home / "apps" / "exec-test" / "app.py"
        mode = app_py.stat().st_mode
        assert mode & stat.S_IXUSR  # User execute bit

    def test_cache_json_is_valid(self, scry_run_home):
        """Test cache.json is valid JSON."""
        import json

        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--name", "json-test", "--description", "Test"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0

        cache_file = scry_run_home / "apps" / "json-test" / "cache.json"
        data = json.loads(cache_file.read_text())
        assert data == {}


class TestMultipleApps:
    """Test workflows with multiple apps."""

    def test_create_multiple_apps(self, scry_run_home):
        """Test creating multiple apps."""
        env = {**os.environ, "SCRY_HOME": str(scry_run_home)}

        for name in ["app1", "app2", "app3"]:
            result = subprocess.run(
                ["uv", "run", "scry-run", "init", "--name", name, "--description", f"Test {name}"],
                env=env,
                capture_output=True,
                text=True,
            )
            assert result.returncode == 0, f"Failed to create {name}: {result.stderr}"

        # Verify all apps exist
        apps_dir = scry_run_home / "apps"
        assert (apps_dir / "app1").exists()
        assert (apps_dir / "app2").exists()
        assert (apps_dir / "app3").exists()

        # Verify cache list shows all apps
        result = subprocess.run(
            ["uv", "run", "scry-run", "cache", "list"],
            env=env,
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0
        assert "app1" in result.stdout
        assert "app2" in result.stdout
        assert "app3" in result.stdout


class TestErrorHandling:
    """Test error handling in CLI commands."""

    def test_init_invalid_name(self, scry_run_home):
        """Test init rejects invalid app names."""
        result = subprocess.run(
            ["uv", "run", "scry-run", "init", "--name", "invalid@name!", "--description", "Test"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        assert result.returncode != 0
        assert "alphanumeric" in result.stderr.lower() or "alphanumeric" in result.stdout.lower()

    def test_cache_list_nonexistent_app(self, scry_run_home):
        """Test cache list for nonexistent app."""
        result = subprocess.run(
            ["uv", "run", "scry-run", "cache", "list", "nonexistent"],
            env={**os.environ, "SCRY_HOME": str(scry_run_home)},
            capture_output=True,
            text=True,
        )
        # Should either return 0 with "not found" message or non-zero exit
        assert "not found" in result.stdout.lower() or result.returncode != 0
