"""Docker Compose linter — 12 rules for Compose best practices."""

from __future__ import annotations

from ..models import Finding, LintRule, Severity

RULES: dict[str, LintRule] = {
    "DC001": LintRule("DC001", "Security", Severity.HIGH, "Using :latest tag", "Service image uses :latest or no tag", "Pin to a specific version"),
    "DC002": LintRule("DC002", "Security", Severity.CRITICAL, "Privileged mode", "Container running in privileged mode", "Remove privileged: true"),
    "DC003": LintRule("DC003", "Reliability", Severity.MEDIUM, "No restart policy", "Service missing restart policy", "Add restart: unless-stopped or restart: always"),
    "DC004": LintRule("DC004", "Reliability", Severity.MEDIUM, "No healthcheck", "Service has no healthcheck defined", "Add healthcheck with test command"),
    "DC005": LintRule("DC005", "Security", Severity.HIGH, "Secrets in environment", "Hardcoded secrets in environment variables", "Use Docker secrets or .env file with env_file"),
    "DC006": LintRule("DC006", "Best Practice", Severity.LOW, "No resource limits", "Service has no resource limits (deploy.resources.limits)", "Add deploy.resources.limits for cpu and memory"),
    "DC007": LintRule("DC007", "Security", Severity.MEDIUM, "Exposing all ports to host", "Using ports instead of expose for internal services", "Use expose for internal services, ports only for external"),
    "DC008": LintRule("DC008", "Best Practice", Severity.INFO, "Using version key", "Obsolete 'version' key in Compose file (v2+)", "Remove version key — Compose automatically detects"),
    "DC009": LintRule("DC009", "Security", Severity.HIGH, "Host volume with write access", "Host path mounted with write access", "Use read-only mounts where possible (:ro)"),
    "DC010": LintRule("DC010", "Best Practice", Severity.LOW, "No logging configuration", "Service has no logging driver configured", "Add logging driver and options"),
    "DC011": LintRule("DC011", "Reliability", Severity.MEDIUM, "No depends_on", "Service with database deps but no depends_on", "Add depends_on with condition: service_healthy"),
    "DC012": LintRule("DC012", "Security", Severity.MEDIUM, "Network mode host", "Service using network_mode: host", "Use custom bridge networks instead"),
}


def lint_compose(docs: list[dict], file_path: str = "") -> list[Finding]:
    """Lint Docker Compose files."""
    findings: list[Finding] = []

    for doc in docs:
        if not isinstance(doc, dict):
            continue

        # DC008: version key
        if "version" in doc:
            findings.append(Finding(rule=RULES["DC008"], line=0, message="Obsolete 'version' key — Compose v2+ auto-detects"))

        services = doc.get("services", {}) or {}
        if not services:
            continue

        for svc_name, svc in services.items():
            if not isinstance(svc, dict):
                continue
            prefix = f"services.{svc_name}"

            # DC001: :latest tag
            image = svc.get("image", "")
            if image and (":" not in image or image.endswith(":latest")):
                findings.append(Finding(rule=RULES["DC001"], line=0, message=f"{prefix}: Image '{image}' uses :latest or no tag"))

            # DC002: Privileged
            if svc.get("privileged"):
                findings.append(Finding(rule=RULES["DC002"], line=0, message=f"{prefix}: Running in privileged mode"))

            # DC003: Restart policy
            if not svc.get("restart") and not (svc.get("deploy", {}) or {}).get("restart_policy"):
                findings.append(Finding(rule=RULES["DC003"], line=0, message=f"{prefix}: No restart policy defined"))

            # DC004: Healthcheck
            if not svc.get("healthcheck"):
                findings.append(Finding(rule=RULES["DC004"], line=0, message=f"{prefix}: No healthcheck configured"))

            # DC005: Secrets in environment
            env = svc.get("environment", {})
            env_items = []
            if isinstance(env, dict):
                env_items = list(env.items())
            elif isinstance(env, list):
                for e in env:
                    if "=" in str(e):
                        k, v = str(e).split("=", 1)
                        env_items.append((k, v))

            for k, v in env_items:
                k_upper = k.upper()
                if any(kw in k_upper for kw in ("PASSWORD", "SECRET", "TOKEN", "API_KEY", "PRIVATE_KEY")) and v:
                    findings.append(Finding(rule=RULES["DC005"], line=0, message=f"{prefix}: Potential secret '{k}' hardcoded in environment"))

            # DC006: Resource limits
            deploy = svc.get("deploy", {}) or {}
            if not deploy.get("resources", {}).get("limits"):
                findings.append(Finding(rule=RULES["DC006"], line=0, message=f"{prefix}: No resource limits set"))

            # DC007: Ports exposed to all interfaces (0.0.0.0)
            ports = svc.get("ports", []) or []
            for p in ports:
                p_str = str(p)
                if "0.0.0.0" in p_str:
                    findings.append(Finding(rule=RULES["DC007"], line=0, message=f"{prefix}: Port '{p_str}' binds to all interfaces"))
                    break

            # DC009: Host volume with write
            volumes = svc.get("volumes", []) or []
            for vol in volumes:
                vol_str = str(vol)
                if ("/" in vol_str or "\\" in vol_str) and ":ro" not in vol_str and ":r" not in vol_str:
                    if ":" in vol_str:
                        findings.append(Finding(rule=RULES["DC009"], line=0, message=f"{prefix}: Host volume '{vol_str}' mounted read-write"))
                        break

            # DC010: Logging
            if not svc.get("logging"):
                findings.append(Finding(rule=RULES["DC010"], line=0, message=f"{prefix}: No logging configuration"))

            # DC012: network_mode host
            if svc.get("network_mode") == "host":
                findings.append(Finding(rule=RULES["DC012"], line=0, message=f"{prefix}: Using network_mode: host"))

    return findings
