"""Graph preset model for persisted graph configurations."""
from datetime import UTC, datetime
from functools import partial
from typing import Annotated, Dict, List, Literal, Optional

from pydantic import BaseModel, Field, StringConstraints

from .base import BaseDocument
from .types import PyObjectId


DateFilterMode = Literal["preset", "custom"]
TimeframePreset = Literal["all", "1m", "3m", "6m", "12m"]
GraphDatasetType = Literal["medication", "line"]
GraphLineStyle = Literal["solid", "dashed", "dotted"]
GraphPointStyle = Literal["circle", "square", "none"]


class GraphPresetDateRange(BaseModel):
    """A date range used by dataset or graph creation metadata."""
    startDate: Optional[str] = None
    endDate: Optional[str] = None


class GraphDatasetOrigin(BaseModel):
    """Origin metadata for each dataset included in a graph preset."""
    dateFilterMode: DateFilterMode = "preset"
    selectedPreset: Optional[TimeframePreset] = None
    appliedDateRange: GraphPresetDateRange = Field(default_factory=GraphPresetDateRange)


class GraphCreationContext(BaseModel):
    """Creation context metadata for a graph."""
    datasetIds: List[str] = Field(default_factory=list)
    datasetNames: List[str] = Field(default_factory=list)
    dateFilterMode: Optional[DateFilterMode] = None
    selectedPreset: Optional[TimeframePreset] = None
    appliedDateRange: Optional[GraphPresetDateRange] = None
    datasetOrigins: Dict[str, GraphDatasetOrigin] = Field(default_factory=dict)
    searchQuery: Optional[str] = None


class GraphDatasetConfig(BaseModel):
    """Dataset configuration as exported by the graph page."""
    id: Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)]
    name: Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)]
    type: GraphDatasetType
    unit: str = ""
    color: Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)]
    lineStyle: Optional[GraphLineStyle] = None
    pointStyle: Optional[GraphPointStyle] = None
    dateFilterMode: DateFilterMode = "preset"
    selectedPreset: Optional[TimeframePreset] = None
    appliedDateRange: GraphPresetDateRange = Field(default_factory=GraphPresetDateRange)


class GraphPresetGraph(BaseModel):
    """One graph entry inside a graph preset."""
    id: Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)]
    normalizeByReference: bool = False
    datasets: List[GraphDatasetConfig] = Field(default_factory=list)
    creation: Optional[GraphCreationContext] = None


class GraphPreset(BaseDocument):
    """Persisted graph preset tied to a patient user."""
    patientId: PyObjectId = Field(description="ID of the patient owning this preset")
    name: Annotated[str, StringConstraints(min_length=1, strip_whitespace=True)] = Field(
        description="Human-friendly preset name"
    )
    exportedAt: datetime = Field(default_factory=partial(datetime.now, UTC))
    graphCount: int = 0
    graphs: List[GraphPresetGraph] = Field(default_factory=list)
