"""Tests for Phase 4 Stream E: deploy CLI, updated init templates, stale container cleanup."""

from __future__ import annotations

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

import yaml
from click.testing import CliRunner

from loom.cli import cli


class TestDeployCLI:
    def test_deploy_help(self):
        """loom deploy --help shows expected options."""
        runner = CliRunner()
        result = runner.invoke(cli, ["deploy", "--help"])
        assert result.exit_code == 0
        assert "--project" in result.output
        assert "--region" in result.output
        assert "--tag" in result.output
        assert "GCP Cloud Run" in result.output

    def test_deploy_requires_project(self, monkeypatch):
        """Deploy fails gracefully when no GCP project is set."""
        monkeypatch.delenv("LOOM_GCP_PROJECT", raising=False)
        runner = CliRunner()
        result = runner.invoke(cli, ["deploy"])
        assert result.exit_code != 0
        assert "GCP project required" in result.output


class TestInitTemplates:
    def test_agents_md_includes_all_tools(self, tmp_path, monkeypatch):
        """Generated AGENTS.md includes Phase 3+4 MCP tools."""
        monkeypatch.chdir(tmp_path)
        runner = CliRunner()
        result = runner.invoke(cli, ["init", "--name", "test-proj"])
        assert result.exit_code == 0

        agents_md = (tmp_path / "AGENTS.md").read_text()
        # Phase 1 tools
        assert "loom_ready" in agents_md
        assert "loom_claim" in agents_md
        assert "loom_done" in agents_md
        assert "loom_fail" in agents_md
        assert "loom_escalate" in agents_md
        assert "loom_create" in agents_md
        assert "loom_status" in agents_md
        assert "loom_message" in agents_md
        assert "loom_graph" in agents_md
        assert "loom_update" in agents_md
        # Phase 2+3 tools
        assert "loom_decompose" in agents_md
        assert "loom_heartbeat" in agents_md
        assert "loom_orchestrate" in agents_md
        assert "loom_workflow" in agents_md
        assert "loom_dead_letter" in agents_md

    def test_agents_md_includes_cli_commands(self, tmp_path, monkeypatch):
        """Generated AGENTS.md includes CLI commands section."""
        monkeypatch.chdir(tmp_path)
        runner = CliRunner()
        runner.invoke(cli, ["init", "--name", "test-proj"])

        agents_md = (tmp_path / "AGENTS.md").read_text()
        assert "CLI Commands" in agents_md
        assert "loom deploy" in agents_md
        assert "loom digest" in agents_md
        assert "loom orchestrate" in agents_md

    def test_docker_compose_has_mcp_service(self, tmp_path, monkeypatch):
        """Generated docker-compose includes loom-mcp service with mcp profile."""
        monkeypatch.chdir(tmp_path)
        runner = CliRunner()
        runner.invoke(cli, ["init", "--name", "test-proj"])

        compose_path = tmp_path / "docker-compose.loom.yml"
        assert compose_path.exists()

        with open(compose_path) as f:
            compose = yaml.safe_load(f)

        services = compose["services"]
        assert "postgres" in services
        assert "redis" in services
        assert "loom-mcp" in services

        mcp_svc = services["loom-mcp"]
        assert mcp_svc["profiles"] == ["mcp"]
        assert "postgres" in mcp_svc["depends_on"]
        assert "redis" in mcp_svc["depends_on"]
        assert "LOOM_DATABASE_URL" in mcp_svc["environment"]
        assert "LOOM_REDIS_URL" in mcp_svc["environment"]

    def test_docker_compose_mcp_service_has_build_context(self, tmp_path, monkeypatch):
        """loom-mcp service has a build context for local Docker builds."""
        monkeypatch.chdir(tmp_path)
        runner = CliRunner()
        runner.invoke(cli, ["init", "--name", "test-proj"])

        with open(tmp_path / "docker-compose.loom.yml") as f:
            compose = yaml.safe_load(f)

        mcp_svc = compose["services"]["loom-mcp"]
        assert mcp_svc["build"]["dockerfile"] == "Dockerfile"


class TestStaleContainerCleanup:
    def test_cleanup_stale_reaper_runs(self):
        """_cleanup_stale_reaper runs without error even with no stale containers."""
        from tests.conftest import _cleanup_stale_reaper
        # Should not raise
        _cleanup_stale_reaper()

    def test_cleanup_handles_no_docker(self):
        """_cleanup_stale_reaper handles Docker not available."""
        from tests.conftest import _cleanup_stale_reaper
        with patch("tests.conftest.subprocess.run", side_effect=FileNotFoundError):
            # Should not raise
            _cleanup_stale_reaper()
