from pathlib import Path

import pytest


NGINX_CONFIG = """server {
    listen 80;
    server_name mo.wooo.work;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name mo.wooo.work;

    location / {
        proxy_pass http://127.0.0.1:5003;
    }
}
"""

NGINX_FRAGMENT = """location = /metrics {
    allow 127.0.0.1;
    allow 172.16.0.0/12;
    deny all;
    proxy_pass http://127.0.0.1:5003/metrics;
}
"""

PROMETHEUS_CONFIG = """global:
  scrape_interval: 60s

scrape_configs:
  - job_name: existing
    static_configs:
      - targets: ['127.0.0.1:9090']
"""

PROMETHEUS_SNIPPET = """  - job_name: 'ewoooc-app'
    scheme: http
    metrics_path: /metrics
    static_configs:
      - targets: ['172.20.0.1:19191']
"""

NGINX_BRIDGE = """server {
    listen 172.20.0.1:19191;
    server_name ewooooc-metrics.internal;
    location = /metrics {
        allow 172.16.0.0/12;
        deny all;
        proxy_pass https://192.168.0.188/metrics;
    }
}
"""


def test_render_nginx_config_targets_only_tls_server_and_is_idempotent():
    from services.metrics_edge_controlled_apply_service import render_nginx_config

    rendered = render_nginx_config(NGINX_CONFIG, NGINX_FRAGMENT)
    second = render_nginx_config(rendered, NGINX_FRAGMENT)

    assert rendered == second
    assert rendered.count("location = /metrics") == 1
    assert rendered.index("listen 443") < rendered.index("location = /metrics")
    assert rendered.index("location = /metrics") < rendered.index("location / {")


def test_render_prometheus_config_is_idempotent():
    from services.metrics_edge_controlled_apply_service import render_prometheus_config

    rendered = render_prometheus_config(PROMETHEUS_CONFIG, PROMETHEUS_SNIPPET)
    second = render_prometheus_config(rendered, PROMETHEUS_SNIPPET)

    assert rendered == second
    assert rendered.count("job_name: 'ewoooc-app'") == 1


def test_render_standalone_nginx_bridge_is_idempotent():
    from services.metrics_edge_controlled_apply_service import render_nginx_config

    rendered = render_nginx_config("", NGINX_BRIDGE)
    second = render_nginx_config(rendered, NGINX_BRIDGE)

    assert rendered == second
    assert rendered.count("listen 172.20.0.1:19191") == 1


def test_build_plan_is_no_write_and_commit_safe(tmp_path: Path):
    from services.metrics_edge_controlled_apply_service import build_metrics_edge_plan

    paths = {
        "nginx_config": tmp_path / "nginx.conf",
        "prometheus_config": tmp_path / "prometheus.yml",
        "nginx_fragment": tmp_path / "location.conf",
        "prometheus_snippet": tmp_path / "scrape.yml",
    }
    paths["nginx_config"].write_text(NGINX_CONFIG, encoding="utf-8")
    paths["prometheus_config"].write_text(PROMETHEUS_CONFIG, encoding="utf-8")
    paths["nginx_fragment"].write_text(NGINX_FRAGMENT, encoding="utf-8")
    paths["prometheus_snippet"].write_text(PROMETHEUS_SNIPPET, encoding="utf-8")

    plan = build_metrics_edge_plan(
        **paths,
        run_id="sec-p0-001-test",
        work_item_id="SEC-P0-001",
    )

    assert plan["mode"] == "check"
    assert plan["nginx"]["changed"] is True
    assert plan["prometheus"]["changed"] is True
    assert paths["nginx_config"].read_text(encoding="utf-8") == NGINX_CONFIG


def test_prometheus_write_preserves_bind_mount_inode(tmp_path: Path):
    from services.metrics_edge_controlled_apply_service import _inplace_write

    config = tmp_path / "prometheus.yml"
    config.write_text(PROMETHEUS_CONFIG, encoding="utf-8")
    inode_before = config.stat().st_ino

    _inplace_write(config, "global:\n  scrape_interval: 30s\n")

    assert config.stat().st_ino == inode_before
    assert config.read_text(encoding="utf-8") == "global:\n  scrape_interval: 30s\n"


def test_prometheus_config_sha_detects_stale_container_mount(tmp_path: Path, monkeypatch):
    from services import metrics_edge_controlled_apply_service as service

    config = tmp_path / "prometheus.yml"
    config.write_text("candidate", encoding="utf-8")
    stale_sha = "0" * 64
    monkeypatch.setattr(
        service,
        "_run",
        lambda _command: type("Completed", (), {"stdout": f"{stale_sha}  config"})(),
    )

    host_sha, container_sha = service._prometheus_config_sha(config)

    assert host_sha != container_sha
    assert container_sha == stale_sha


def test_metrics_canary_requires_ewoooc_product_markers():
    from services.metrics_edge_controlled_apply_service import _parse_metrics_canary

    valid = (
        "momo_app_info 1\nmomo_app_health 1\nmomo_database_up 1"
        "\n__EWOOOC_HTTP_STATUS__:200"
    )
    wrong_exporter = "fail2ban_total_failed 0\n__EWOOOC_HTTP_STATUS__:200"

    assert _parse_metrics_canary(valid) == ("200", True)
    assert _parse_metrics_canary(wrong_exporter) == ("200", False)


def test_metrics_canary_waits_for_new_nginx_worker(monkeypatch):
    from services import metrics_edge_controlled_apply_service as service

    outputs = iter([
        "forbidden\n__EWOOOC_HTTP_STATUS__:403",
        (
            "momo_app_info 1\nmomo_app_health 1\nmomo_database_up 1"
            "\n__EWOOOC_HTTP_STATUS__:200"
        ),
    ])

    monkeypatch.setattr(
        service,
        "_run",
        lambda _command: type("Completed", (), {"stdout": next(outputs)})(),
    )
    monkeypatch.setattr(service.time, "sleep", lambda _seconds: None)

    assert service._wait_metrics_canary(["curl"], 10) == ("200", True, 2)


def test_target_health_rejects_stale_scrape_url():
    from services.metrics_edge_controlled_apply_service import _target_health_from_payload

    payload = {
        "data": {
            "activeTargets": [
                {
                    "labels": {"job": "ewoooc-app"},
                    "scrapeUrl": "http://172.20.0.1:9191/metrics",
                    "health": "up",
                },
                {
                    "labels": {"job": "ewoooc-app"},
                    "scrapeUrl": "http://172.20.0.1:19191/metrics",
                    "health": "down",
                },
            ]
        }
    }

    health = _target_health_from_payload(
        payload,
        "http://172.20.0.1:19191/metrics",
    )

    assert health == "down"


def test_prometheus_identity_verifier_requires_same_image_and_data_volume():
    from services.metrics_edge_controlled_apply_service import (
        _prometheus_identity_preserved,
    )

    before = {"image_id": "image-a", "data_volume": "volume-a"}

    assert _prometheus_identity_preserved(before, dict(before)) is True
    assert _prometheus_identity_preserved(
        before,
        {"image_id": "image-b", "data_volume": "volume-a"},
    ) is False
    assert _prometheus_identity_preserved(
        before,
        {"image_id": "image-a", "data_volume": "volume-b"},
    ) is False


def test_render_rejects_incomplete_templates():
    from services.metrics_edge_controlled_apply_service import (
        render_nginx_config,
        render_prometheus_config,
    )

    with pytest.raises(ValueError, match="incomplete"):
        render_nginx_config(NGINX_CONFIG, "location = /metrics {}")
    with pytest.raises(ValueError, match="incomplete"):
        render_prometheus_config(PROMETHEUS_CONFIG, "job_name: other")
