from __future__ import annotations

from datetime import datetime

from pydantic import BaseModel, Field


class Alert(BaseModel):
    status: str
    """'firing' or 'resolved'"""

    labels: dict[str, str] = Field(default_factory=dict)
    """Key/value pairs defined on the alert rule (e.g. alertname, severity, app)."""

    annotations: dict[str, str] = Field(default_factory=dict)
    """Human-readable fields like summary, description, runbook_url."""

    starts_at: datetime = Field(alias="startsAt")
    ends_at: datetime = Field(alias="endsAt")

    generator_url: str = Field(default="", alias="generatorURL")
    """Deep-link into Grafana Explore for the alert query."""

    fingerprint: str = ""
    """Unique hash identifying this specific alert instance."""

    silence_url: str = Field(default="", alias="silenceURL")
    """Pre-built URL to create a silence for this alert in Grafana."""

    dashboard_url: str = Field(default="", alias="dashboardURL")
    panel_url: str = Field(default="", alias="panelURL")

    values: dict[str, float | None] = Field(default_factory=dict)
    """Actual metric values that triggered the alert, keyed by query ref (e.g. 'B')."""

    value_string: str = Field(default="", alias="valueString")
    """Human-readable representation of values, e.g. '[ var='B' value=95.3 ]'."""

    model_config = {"populate_by_name": True}

    @property
    def is_firing(self) -> bool:
        return self.status == "firing"

    @property
    def is_resolved(self) -> bool:
        return self.status == "resolved"

    @property
    def summary(self) -> str:
        return self.annotations.get("summary", "")

    @property
    def description(self) -> str:
        return self.annotations.get("description", "")

    @property
    def alertname(self) -> str:
        return self.labels.get("alertname", "")

    @property
    def app(self) -> str:
        return self.labels.get("app", "")

    @property
    def severity(self) -> str:
        return self.labels.get("severity", "")


class GrafanaWebhookPayload(BaseModel):
    """
    Grafana Unified Alerting webhook payload (Grafana 9+).

    Grafana fires this as a POST request to your configured contact point URL
    whenever an alert group changes state (firing → resolved or vice versa).
    """

    receiver: str
    """Name of the contact point that triggered this webhook."""

    status: str
    """Overall group status: 'firing' if any alert is firing, else 'resolved'."""

    alerts: list[Alert] = Field(default_factory=list)
    """All alerts in this notification group."""

    group_labels: dict[str, str] = Field(default_factory=dict, alias="groupLabels")
    """Labels used to group alerts together (defined in the alert rule's group-by)."""

    common_labels: dict[str, str] = Field(default_factory=dict, alias="commonLabels")
    """Labels shared by every alert in this payload."""

    common_annotations: dict[str, str] = Field(default_factory=dict, alias="commonAnnotations")
    """Annotations shared by every alert in this payload."""

    external_url: str = Field(default="", alias="externalURL")
    """Base URL of the Grafana instance."""

    version: str = "1"
    group_key: str = Field(default="", alias="groupKey")

    truncated_alerts: int = Field(default=0, alias="truncatedAlerts")
    """Number of alerts omitted from this payload due to size limits."""

    org_id: int = Field(default=0, alias="orgId")

    title: str = ""
    """Pre-formatted title, e.g. '[FIRING:1] HighCPU (critical)'."""

    state: str = ""
    """Alert state string, e.g. 'alerting'."""

    message: str = ""
    """Pre-formatted Markdown message body."""

    model_config = {"populate_by_name": True}

    @property
    def is_firing(self) -> bool:
        return self.status == "firing"

    @property
    def firing_alerts(self) -> list[Alert]:
        return [a for a in self.alerts if a.is_firing]

    @property
    def resolved_alerts(self) -> list[Alert]:
        return [a for a in self.alerts if a.is_resolved]
