"""Grafana visualization and dashboarding module.

Auto-provisions datasources (Prometheus, Loki, Tempo) and
generates per-service dashboards from module configurations.
"""

from __future__ import annotations

from typing import Any

from nikame.modules.base import BaseModule, ModuleContext


class GrafanaModule(BaseModule):
    """Grafana dashboarding module.

    Auto-configures Prometheus datasource and provisions dashboards
    generated by each module in the blueprint.
    """

    NAME = "grafana"
    CATEGORY = "observability"
    DESCRIPTION = "Grafana dashboards with auto-provisioned datasources"
    DEFAULT_VERSION = "10.2.0"
    DEPENDENCIES = ["prometheus"]
    CONFLICTS: list[str] = []

    def __init__(self, config: dict[str, Any], ctx: ModuleContext) -> None:
        super().__init__(config, ctx)
        self.admin_password: str = "${GRAFANA_ADMIN_PASSWORD}"

    def required_ports(self) -> dict[str, int]:
        """Standard Grafana port."""
        return {"grafana": 3000}

    def compose_spec(self) -> dict[str, Any]:
        """Generate Docker Compose service spec for Grafana."""
        return {
            "grafana": {
                "image": f"grafana/grafana:{self.version}",
                "restart": "unless-stopped",
                "environment": {
                    "GF_SECURITY_ADMIN_USER": "admin",
                    "GF_SECURITY_ADMIN_PASSWORD": self.admin_password,
                    "GF_USERS_ALLOW_SIGN_UP": "false",
                    "GF_SERVER_ROOT_URL": f"http://{self.ctx.domain or 'localhost'}:3000",
                },
                "ports": [f"{self.ctx.host_port_map.get('grafana', 3000)}:3000"] if self.ctx.environment == "local" else [],
                "volumes": [
                    "grafana_data:/var/lib/grafana",
                    "./configs/grafana/provisioning/:/etc/grafana/provisioning/:ro",
                    "./configs/grafana/dashboards/:/var/lib/grafana/dashboards/:ro",
                ],
                "depends_on": {"prometheus": {"condition": "service_healthy"}},
                "healthcheck": self.health_check(),
                "networks": [f"{self.ctx.project_name}_network"],
                "labels": {
                    "nikame.module": "grafana",
                    "nikame.category": "observability",
                },
            }
        }

    def k8s_manifests(self) -> list[dict[str, Any]]:
        """Generate K8s Deployment + Service for Grafana."""
        deployment: dict[str, Any] = {
            "apiVersion": "apps/v1",
            "kind": "Deployment",
            "metadata": {"name": "grafana", "namespace": self.ctx.namespace},
            "spec": {
                "replicas": 1,
                "selector": {"matchLabels": {"app": "grafana"}},
                "template": {
                    "metadata": {"labels": {"app": "grafana"}},
                    "spec": {
                        "containers": [
                            {
                                "name": "grafana",
                                "image": f"grafana/grafana:{self.version}",
                                "ports": [{"containerPort": 3000}],
                                "envFrom": [{"secretRef": {"name": "grafana-secret"}}],
                                "volumeMounts": [
                                    {"name": "data", "mountPath": "/var/lib/grafana"},
                                    {"name": "dashboards", "mountPath": "/var/lib/grafana/dashboards"},
                                    {"name": "provisioning", "mountPath": "/etc/grafana/provisioning"},
                                ],
                                "resources": self.resource_requirements(),
                            }
                        ],
                        "volumes": [
                            {"name": "data", "persistentVolumeClaim": {"claimName": "grafana-pvc"}},
                            {"name": "dashboards", "configMap": {"name": "grafana-dashboards"}},
                            {"name": "provisioning", "configMap": {"name": "grafana-provisioning"}},
                        ],
                    },
                },
            },
        }

        service: dict[str, Any] = {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {"name": "grafana", "namespace": self.ctx.namespace},
            "spec": {
                "selector": {"app": "grafana"},
                "ports": [{"port": 3000, "targetPort": 3000}],
            },
        }

        return [deployment, service]

    def health_check(self) -> dict[str, Any]:
        """Grafana health endpoint."""
        return {
            "test": ["CMD", "curl", "-f", "http://localhost:3000/api/health"],
            "interval": "15s",
            "timeout": "10s",
            "retries": 3,
            "start_period": "30s",
        }

    def env_vars(self) -> dict[str, str]:
        """Grafana URL for other services."""
        return {
            "GRAFANA_URL": "http://grafana:3000",
        }

    def init_scripts(self) -> list[tuple[str, str]]:
        """Generate Grafana provisioning config files."""
        # Datasource provisioning YAML
        datasource_yaml = """apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    editable: false
"""
        # Dashboard provider YAML
        dashboard_provider_yaml = """apiVersion: 1
providers:
  - name: NIKAME Dashboards
    orgId: 1
    folder: NIKAME
    type: file
    disableDeletion: false
    editable: true
    options:
      path: /var/lib/grafana/dashboards
      foldersFromFilesStructure: false
"""
        return [
            ("provisioning/datasources/datasources.yml", datasource_yaml),
            ("provisioning/dashboards/dashboards.yml", dashboard_provider_yaml),
        ]

    def prometheus_rules(self) -> list[dict[str, Any]]:
        """Prometheus alerts for Grafana."""
        return [
            {
                "alert": "GrafanaDown",
                "expr": "up{job='grafana'} == 0",
                "for": "1m",
                "labels": {"severity": "critical"},
                "annotations": {"summary": "Grafana is down"},
            },
        ]

    def grafana_dashboard(self) -> dict[str, Any] | None:
        """No self-referential dashboard needed."""
        return None

    def compute_cost_monthly_usd(self) -> float | None:
        """Estimate monthly cost."""
        return 5.0

    def resource_requirements(self) -> dict[str, Any]:
        """K8s resources for Grafana."""
        return {
            "requests": {"cpu": "100m", "memory": "256Mi"},
            "limits": {"cpu": "500m", "memory": "512Mi"},
        }
