"""Tests for roustabout renderer."""

import pytest

from roustabout.models import (
    MountInfo,
    NetworkMembership,
    PortBinding,
    make_container,
    make_environment,
)
from roustabout.renderer import render


def _full_environment():
    """Build a multi-container environment for rendering tests."""
    nginx = make_container(
        name="nginx-proxy",
        id="abc123",
        status="running",
        image="nginx:1.25-alpine",
        image_id="sha256:abc",
        image_digest="nginx@sha256:deadbeef",
        ports=[
            PortBinding(container_port=443, protocol="tcp", host_ip="0.0.0.0", host_port="8443"),
            PortBinding(container_port=80, protocol="tcp", host_ip="0.0.0.0", host_port="8080"),
        ],
        mounts=[
            MountInfo(
                source="/opt/nginx.conf",
                destination="/etc/nginx/nginx.conf",
                mode="ro",
                type="bind",
            ),
        ],
        networks=[
            NetworkMembership(name="frontend", ip_address="172.18.0.2", aliases=("proxy",)),
            NetworkMembership(name="backend", ip_address="172.18.1.2", aliases=()),
        ],
        env=[("NGINX_HOST", "example.com"), ("SECRET_KEY", "[REDACTED]")],
        labels=[
            ("com.docker.compose.project", "webstack"),
            ("com.docker.compose.service", "nginx"),
            ("maintainer", "ops@example.com"),
        ],
        health="healthy",
        compose_project="webstack",
        compose_service="nginx",
        compose_config_files="/opt/docker-compose.yml",
        created="2026-02-01T10:00:00Z",
        started_at="2026-02-01T10:00:05Z",
        command=["nginx", "-g", "daemon off;"],
        entrypoint=["/docker-entrypoint.sh"],
    )

    postgres = make_container(
        name="postgres-db",
        id="def456",
        status="running",
        image="postgres:16-alpine",
        image_id="sha256:def",
        ports=[
            PortBinding(
                container_port=5432, protocol="tcp", host_ip="127.0.0.1", host_port="5432"
            ),
        ],
        networks=[
            NetworkMembership(name="backend", ip_address="172.18.1.3", aliases=("db",)),
        ],
        env=[("POSTGRES_PASSWORD", "[REDACTED]"), ("POSTGRES_USER", "app")],
        compose_project="webstack",
        compose_service="postgres",
        compose_config_files="/opt/docker-compose.yml",
        created="2026-02-01T10:00:00Z",
        started_at="2026-02-01T10:00:03Z",
        command=["postgres"],
    )

    watchtower = make_container(
        name="watchtower",
        id="ghi789",
        status="running",
        image="containrrr/watchtower:latest",
        image_id="sha256:ghi",
        mounts=[
            MountInfo(
                source="/var/run/docker.sock",
                destination="/var/run/docker.sock",
                mode="rw",
                type="bind",
            ),
        ],
        networks=[
            NetworkMembership(name="bridge", ip_address="172.17.0.2", aliases=()),
        ],
        env=[("WATCHTOWER_CLEANUP", "true")],
        created="2026-02-01T10:00:00Z",
        started_at="2026-02-01T10:00:01Z",
        command=["--cleanup"],
        entrypoint=["/watchtower"],
    )

    stopped = make_container(
        name="redis-cache",
        id="jkl012",
        status="exited",
        image="redis:7-alpine",
        image_id="sha256:jkl",
        compose_project="webstack",
        compose_service="redis",
        created="2026-01-15T08:00:00Z",
        started_at="2026-01-15T08:00:01Z",
        oom_killed=True,
    )

    return make_environment(
        containers=[nginx, postgres, watchtower, stopped],
        generated_at="2026-02-28T12:00:00Z",
        docker_version="25.0.3",
    )


class TestDocumentStructure:
    def test_header_and_metadata(self):
        output = render(_full_environment())
        assert output.startswith("# Docker Environment\n")
        assert "**Generated:** 2026-02-28T12:00:00Z" in output
        assert "**Docker version:** 25.0.3" in output
        assert "**Containers:** 4 total, 3 running" in output

    def test_toc_with_status_markers(self):
        output = render(_full_environment())
        assert "## Contents" in output
        assert "- [nginx-proxy](#nginx-proxy)" in output
        assert "- [watchtower](#watchtower)" in output
        assert "- [redis-cache](#redis-cache) (exited)" in output

    def test_attribution_comment(self):
        output = render(_full_environment())
        assert output.strip().endswith(
            "<!-- Generated by roustabout (https://github.com/FeatureCreep-dev/roustabout) -->"
        )

    def test_network_topology_section(self):
        output = render(_full_environment())
        assert "## Network Topology" in output
        assert "**backend:**" in output
        assert "**frontend:**" in output
        assert "**bridge:**" in output


class TestComposeGrouping:
    def test_grouped_containers_under_project_heading(self):
        output = render(_full_environment())
        assert "## Compose Project: webstack" in output
        assert "### nginx-proxy" in output
        assert "### postgres-db" in output
        assert "Config: `/opt/docker-compose.yml`" in output

    def test_ungrouped_containers_at_top_level(self):
        output = render(_full_environment())
        assert "## watchtower" in output


class TestContainerSections:
    def test_ports_table(self):
        output = render(_full_environment())
        assert "| 80 | 0.0.0.0:8080 | tcp |" in output
        assert "| 443 | 0.0.0.0:8443 | tcp |" in output

    def test_no_ports_section_when_empty(self):
        c = make_container(
            name="test", id="abc", status="running", image="img", image_id="sha256:123"
        )
        env = make_environment(
            containers=[c], generated_at="2026-01-01T00:00:00Z", docker_version="25.0"
        )
        assert "#### Ports" not in render(env)

    def test_mounts_table(self):
        output = render(_full_environment())
        assert "| `/opt/nginx.conf` | `/etc/nginx/nginx.conf` | bind | ro |" in output

    def test_network_with_and_without_aliases(self):
        output = render(_full_environment())
        assert "**frontend:** 172.18.0.2 (aliases: proxy)" in output
        assert "**backend:** 172.18.1.2\n" in output

    def test_metadata_fields(self):
        output = render(_full_environment())
        assert "**OOM Killed:** yes" in output
        assert "**Command:** `nginx -g daemon off;`" in output
        assert "**Entrypoint:** `/docker-entrypoint.sh`" in output
        assert "**Restart count:** 0" in output


class TestEnvToggle:
    def test_env_hidden_by_default(self):
        output = render(_full_environment())
        assert "#### Environment" not in output
        assert "NGINX_HOST" not in output

    def test_env_shown_when_enabled(self):
        output = render(_full_environment(), show_env=True)
        assert "#### Environment" in output
        assert "| `NGINX_HOST` | `example.com` |" in output


class TestLabelsRendering:
    def test_user_labels_shown_compose_labels_excluded(self):
        output = render(_full_environment())
        assert "#### Labels" in output
        assert "| `maintainer` | `ops@example.com` |" in output
        assert "com.docker.compose.project" not in output
        assert "com.docker.compose.service" not in output

    def test_labels_hidden_when_disabled(self):
        assert "#### Labels" not in render(_full_environment(), show_labels=False)


class TestDeterminism:
    @pytest.mark.parametrize("show_env", [False, True])
    def test_render_twice_produces_identical_output(self, show_env):
        env = _full_environment()
        assert render(env, show_env=show_env) == render(env, show_env=show_env)


class TestEmptyEnvironment:
    def test_no_containers(self):
        env = make_environment(
            containers=[], generated_at="2026-01-01T00:00:00Z", docker_version="25.0"
        )
        output = render(env)
        assert "**Containers:** 0 total, 0 running" in output
        assert "## Contents" in output
        assert "## Network Topology" not in output
