"""Integration tests for prepare-task CLI with default context.

NOTE: These tests require a specific test fixture spec
(prepare-task-default-context-2025-11-23-001) to be present.
If the fixture is missing, all tests in this module are skipped.
"""

import json
import subprocess
from pathlib import Path

import pytest

# Check if the required fixture spec exists
REQUIRED_SPEC_ID = "prepare-task-default-context-2025-11-23-001"


def _check_spec_exists() -> bool:
    """Check if the required test fixture spec exists."""
    cmd = ["foundry-cli", "specs", "find"]
    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            cwd=Path(__file__).parent.parent.parent,
            timeout=10,
        )
        if result.returncode == 0:
            specs_data = json.loads(result.stdout)
            spec_ids = [s.get("spec_id", s.get("id", "")) for s in specs_data.get("specs", [])]
            return REQUIRED_SPEC_ID in spec_ids
    except Exception:
        pass
    return False


# Skip entire module if fixture is missing
pytestmark = pytest.mark.skipif(
    not _check_spec_exists(),
    reason=f"Test fixture spec '{REQUIRED_SPEC_ID}' not found. These tests require the Foundry CLI test fixtures.",
)


def run_prepare_task_command(spec_id: str, *args) -> dict:
    """Run foundry tasks prepare command and return parsed JSON output."""
    cmd = ["foundry-cli", "tasks", "prepare", spec_id] + list(args)
    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        cwd=Path(__file__).parent.parent.parent,
    )

    if result.returncode != 0:
        raise RuntimeError(f"Command failed: {' '.join(cmd)}\nstderr: {result.stderr}\nstdout: {result.stdout}")

    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError as e:
        raise RuntimeError(f"Failed to parse JSON output: {result.stdout}") from e


def test_default_payload_no_extra_flags():
    """Test that CLI invocation emits plan/files/validation without extra flags.

    Verifies that the default prepare-task behavior returns:
    - task_id
    - task_data
    - dependencies
    - validation_warnings (only if non-empty, per contract spec)
    - context (with standard fields)

    Without extra fields from enhancement flags like:
    - --include-full-journal
    - --include-phase-history
    - --include-spec-overview
    """
    spec_id = "prepare-task-default-context-2025-11-23-001"

    # Run prepare-task with no enhancement flags
    result = run_prepare_task_command(spec_id)

    # Verify essential fields are present
    assert "task_id" in result
    assert "task_data" in result
    assert "dependencies" in result
    # validation_warnings is only included when non-empty (per contracts.py)
    # So we just verify it's a list if present
    if "validation_warnings" in result:
        assert isinstance(result["validation_warnings"], list)
    assert "context" in result

    # Verify task_data has expected structure
    task_data = result["task_data"]
    assert task_data["type"] in ("task", "verify")  # Either task or verify type
    assert "title" in task_data
    assert "status" in task_data

    # Verify context has standard fields (no enhancement fields)
    context = result["context"]
    standard_fields = {
        "previous_sibling",
        "parent_task",
        "phase",
        "sibling_files",
        "task_journal",
        "dependencies",
    }
    context_keys = set(context.keys())

    # Context should have the standard fields
    for field in standard_fields:
        assert field in context_keys, f"Missing standard field: {field}"

    # Verify no enhanced context fields are present without flags
    enhanced_fields = {
        "previous_sibling_journal",
        "phase_journal",
        "spec_overview",
    }
    for field in enhanced_fields:
        assert field not in context_keys, (
            f"Field '{field}' should not be in default context. "
            f"Use --include-full-journal, --include-phase-history, or "
            f"--include-spec-overview flags instead."
        )


def test_default_payload_has_validation_warnings():
    """Test that default payload handles validation warnings correctly.

    Per contracts.py, validation_warnings is only included when non-empty.
    If present, it should be a list of strings.
    """
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)

    # Per contracts.py, validation_warnings is only included when non-empty
    # If present, verify it's a list of strings
    if "validation_warnings" in result:
        assert isinstance(result["validation_warnings"], list)
        # Check that warnings are strings
        for warning in result["validation_warnings"]:
            assert isinstance(warning, str)


def test_default_payload_includes_dependencies():
    """Test that default payload includes task dependencies."""
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)

    # Verify dependencies structure
    assert "dependencies" in result
    deps = result["dependencies"]

    # Should have dependency fields
    assert "task_id" in deps
    assert "can_start" in deps
    assert "blocked_by" in deps
    assert "soft_depends" in deps

    # can_start should be a boolean
    assert isinstance(deps["can_start"], bool)

    # blocked_by and soft_depends should be lists
    assert isinstance(deps["blocked_by"], list)
    assert isinstance(deps["soft_depends"], list)


def test_default_payload_without_enhancement_flags():
    """Test that enhancement flags are not included by default.

    This test verifies the core requirement: when using prepare-task
    without explicit enhancement flags (--include-full-journal,
    --include-phase-history, --include-spec-overview), the output
    should NOT contain:
    - previous_sibling_journal
    - phase_journal
    - spec_overview
    """
    spec_id = "prepare-task-default-context-2025-11-23-001"

    # Run with NO enhancement flags
    result = run_prepare_task_command(spec_id)

    context = result.get("context", {})

    # These should NOT be present without explicit flags
    assert "previous_sibling_journal" not in context
    assert "phase_journal" not in context
    assert "spec_overview" not in context

    # But extended_context should not exist at all in default output
    assert "extended_context" not in result


def test_context_previous_sibling_has_journal_excerpt():
    """Test that previous_sibling includes journal_excerpt summary."""
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)
    context = result["context"]

    previous_sibling = context.get("previous_sibling")
    if previous_sibling:
        # If there is a previous sibling, verify it has a journal excerpt
        assert "journal_excerpt" in previous_sibling
        excerpt = previous_sibling["journal_excerpt"]

        # Journal excerpt should have summary (not full entry)
        assert "summary" in excerpt
        assert isinstance(excerpt["summary"], str)


def test_context_phase_has_progress_info():
    """Test that phase context includes progress metrics."""
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)
    context = result["context"]

    phase = context.get("phase")
    if phase:  # Phase can be null
        # Verify phase has key fields
        assert "completed_tasks" in phase
        assert "total_tasks" in phase
        assert "percentage" in phase

        # These should be numbers
        assert isinstance(phase["completed_tasks"], int)
        assert isinstance(phase["total_tasks"], int)
        assert isinstance(phase["percentage"], (int, float))


def test_context_sibling_files_is_list():
    """Test that sibling_files is always a list."""
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)
    context = result["context"]

    assert "sibling_files" in context
    assert isinstance(context["sibling_files"], list)


def test_context_task_journal_has_entries():
    """Test that task_journal includes entries list."""
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)
    context = result["context"]

    task_journal = context.get("task_journal")
    assert task_journal is not None

    # Should have entry_count and entries list
    assert "entry_count" in task_journal
    assert "entries" in task_journal
    assert isinstance(task_journal["entries"], list)
    assert isinstance(task_journal["entry_count"], int)

    # Entry count should match entries list length
    assert task_journal["entry_count"] == len(task_journal["entries"])


def test_end_to_end_json_output_pretty():
    """Test that CLI output can be serialized as pretty JSON."""
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)

    # Serialize to pretty JSON
    pretty_json = json.dumps(result, indent=2)

    # Should have newlines (pretty formatting)
    assert "\n" in pretty_json
    assert "  " in pretty_json  # indentation present

    # Should be valid JSON roundtrip
    parsed = json.loads(pretty_json)
    assert parsed == result


def test_end_to_end_json_output_compact():
    """Test that CLI output can be serialized as compact JSON."""
    spec_id = "prepare-task-default-context-2025-11-23-001"

    result = run_prepare_task_command(spec_id)

    # Serialize to compact JSON
    compact_json = json.dumps(result, separators=(",", ":"))

    # Should be smaller than pretty version
    pretty_json = json.dumps(result, indent=2)
    assert len(compact_json) < len(pretty_json)

    # Should be valid JSON roundtrip
    parsed = json.loads(compact_json)
    assert parsed == result


def test_task_info_redundant_with_prepare_task():
    """Test that task-info provides no additional value beyond prepare-task.

    This verifies that the default prepare-task output includes all the
    information that task-info would provide, making task-info redundant
    for standard workflows.
    """
    spec_id = "prepare-task-default-context-2025-11-23-001"

    # Get prepare-task output
    prepare_result = run_prepare_task_command(spec_id)

    # Get task-info output for comparison
    task_id = prepare_result["task_id"]
    task_info_cmd = ["foundry-cli", "tasks", "info", spec_id, task_id, "--json"]
    task_info_result = subprocess.run(
        task_info_cmd,
        capture_output=True,
        text=True,
        cwd=Path(__file__).parent.parent.parent,
    )

    task_info_data = json.loads(task_info_result.stdout)

    # Verify prepare-task.task_data contains same info as task-info
    prepare_task_data = prepare_result["task_data"]

    # Key fields that task-info provides should be in prepare-task output
    assert prepare_task_data["title"] == task_info_data["title"]
    assert prepare_task_data["status"] == task_info_data["status"]

    # Metadata should also be present
    if "metadata" in task_info_data:
        assert "metadata" in prepare_task_data
        # File path should match if present
        if "file_path" in task_info_data["metadata"]:
            assert prepare_task_data["metadata"]["file_path"] == task_info_data["metadata"]["file_path"]


def test_check_deps_redundant_with_prepare_task():
    """Test that check-deps provides no additional value beyond prepare-task.

    This verifies that context.dependencies in prepare-task output provides
    the same dependency information as check-deps, making check-deps redundant.
    """
    spec_id = "prepare-task-default-context-2025-11-23-001"

    # Get prepare-task output
    prepare_result = run_prepare_task_command(spec_id)

    # Get check-deps output for comparison
    task_id = prepare_result["task_id"]
    check_deps_cmd = ["foundry-cli", "check-deps", spec_id, task_id, "--json"]
    check_deps_result = subprocess.run(
        check_deps_cmd,
        capture_output=True,
        text=True,
        cwd=Path(__file__).parent.parent.parent,
    )

    check_deps_data = json.loads(check_deps_result.stdout)

    # Verify prepare-task includes dependency info from check-deps
    prepare_deps = prepare_result["dependencies"]

    # prepare-task should have dependencies with can_start
    assert prepare_deps is not None
    assert "can_start" in prepare_deps

    # The critical field from check-deps (can_start) should match
    assert prepare_deps["can_start"] == check_deps_data["can_start"]

    # prepare-task provides MORE information than check-deps:
    # - task_id, blocked_by, soft_depends, blocks
    assert "task_id" in prepare_deps
    assert "blocked_by" in prepare_deps
    assert "soft_depends" in prepare_deps

    # context.dependencies provides even more detailed info
    context_deps = prepare_result["context"]["dependencies"]
    assert "blocking" in context_deps
    assert "blocked_by_details" in context_deps
    assert "soft_depends" in context_deps
