import json
from typing import Annotated

from pydantic import BaseModel, Field, field_serializer

from kb_dashboard_core.controls.view import KbnControlGroupInput
from kb_dashboard_core.panels.view import KbnBasePanel, KbnSavedObjectMeta
from kb_dashboard_core.shared.view import BaseVwModel, KbnReference, OmitIfNone


class KbnDashboardOptions(BaseModel):
    """Represents the global options for a Kibana dashboard."""

    useMargins: bool
    """Whether to put space between panels in the dashboard."""
    syncColors: bool
    """Applies the same color palette to all panels on the dashboard."""
    syncCursor: bool
    """When you hover your cursor over a time series chart or a heatmap, the cursor on all other related dashboard charts appears."""
    syncTooltips: bool
    """When you hover your cursor over a Lens chart, the tooltips on all other related dashboard charts automatically appear."""
    hidePanelTitles: bool
    """Whether to hide the titles in the panel headers."""


class KbnDashboardSectionGridData(BaseVwModel):
    """Grid metadata for a collapsible dashboard section header."""

    y: int
    i: str


class KbnDashboardSection(BaseVwModel):
    """Represents a collapsible dashboard section in Kibana saved object attributes."""

    title: str
    collapsed: Annotated[bool | None, OmitIfNone()] = None
    gridData: KbnDashboardSectionGridData


class KbnDashboardAttributes(BaseVwModel):
    title: str
    description: str
    panelsJSON: list[KbnBasePanel]
    sections: Annotated[list[KbnDashboardSection] | None, OmitIfNone()] = Field(default=None)
    optionsJSON: KbnDashboardOptions
    kibanaSavedObjectMeta: KbnSavedObjectMeta
    timeRestore: bool
    timeFrom: Annotated[str | None, OmitIfNone()] = Field(default=None)
    timeTo: Annotated[str | None, OmitIfNone()] = Field(default=None)
    version: int
    controlGroupInput: KbnControlGroupInput | None = None

    @field_serializer('panelsJSON', when_used='always')
    def panels_json_stringified(self, panelsJSON: list[KbnBasePanel]) -> str:
        """Kibana wants this field to be stringified JSON."""
        panels_json = [panel.model_dump() for panel in panelsJSON]
        return json.dumps(panels_json)

    @field_serializer('optionsJSON', when_used='always')
    def options_json_stringified(self, optionsJSON: KbnDashboardOptions) -> str:
        """Kibana wants this field to be stringified JSON."""
        return optionsJSON.model_dump_json(by_alias=True)


class KbnDashboard(BaseModel):
    """Represents the top-level Kibana dashboard JSON structure."""

    attributes: KbnDashboardAttributes
    coreMigrationVersion: str
    created_at: str
    created_by: str
    id: str
    managed: bool
    references: list[KbnReference] = Field(default_factory=list)
    type: str
    typeMigrationVersion: str
    updated_at: str
    updated_by: str
    version: str
