"""Views & Visualization models.

Persisted configurations for views, dashboards, charts, and widgets.
All models are tenant-scoped and support soft-delete.
"""

from __future__ import annotations

from django.db import models

from simorgh.core.models import (
    AuditedModel,
    SoftDeleteModel,
    TenantScopedModel,
    TimeStampedModel,
    UUIDModel,
)


class ViewConfiguration(
    UUIDModel,
    TenantScopedModel,
    AuditedModel,
    SoftDeleteModel,
    TimeStampedModel,
):
    """A saved view configuration for an entity.

    Users can create, customize, and share view configurations.
    Each view references an entity (via its dotted name, e.g. "crm.contact")
    and specifies how it should be rendered.
    """

    name = models.CharField(max_length=255)
    entity_name = models.CharField(
        max_length=255,
        help_text="Dotted entity name, e.g. 'crm.contact'",
    )
    view_type = models.CharField(
        max_length=50,
        help_text="View kind: list, board, kanban, calendar, timeline, tree, org_chart, chart",
    )
    config = models.JSONField(
        default=dict,
        help_text="View-type-specific configuration (columns, grouping, filters…)",
    )
    is_default = models.BooleanField(
        default=False,
        help_text="When True, this is the default view for the entity",
    )
    is_system = models.BooleanField(
        default=False,
        help_text="System views cannot be deleted by users",
    )
    visibility = models.CharField(
        max_length=20,
        default="private",
        choices=(
            ("private", "Private"),
            ("workspace", "Workspace"),
            ("tenant", "Tenant"),
        ),
    )
    sort_order = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "vis_view_configuration"
        ordering = ("entity_name", "sort_order", "name")
        indexes = (
            models.Index(fields=["tenant", "entity_name"]),
            models.Index(fields=["tenant", "view_type"]),
        )

    def __str__(self) -> str:
        return f"{self.entity_name} / {self.name} ({self.view_type})"


class ViewFilter(
    UUIDModel,
    TenantScopedModel,
    AuditedModel,
    TimeStampedModel,
):
    """Saved filter set attached to a view configuration."""

    view = models.ForeignKey(
        ViewConfiguration,
        on_delete=models.CASCADE,
        related_name="filters",
    )
    name = models.CharField(max_length=255)
    filter_config = models.JSONField(
        default=dict,
        help_text="Filter rules as a dict: {field: {op: value}}",
    )
    is_default = models.BooleanField(default=False)
    sort_order = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "vis_view_filter"
        ordering = ("view", "sort_order")

    def __str__(self) -> str:
        return f"{self.view.name} / {self.name}"


class DashboardConfiguration(
    UUIDModel,
    TenantScopedModel,
    AuditedModel,
    SoftDeleteModel,
    TimeStampedModel,
):
    """A dashboard layout with widget placements."""

    name = models.CharField(max_length=255)
    label_key = models.CharField(
        max_length=255,
        default="",
        help_text="i18n key for the dashboard title",
    )
    icon = models.CharField(max_length=50, default="grid")
    is_default = models.BooleanField(default=False)
    is_system = models.BooleanField(default=False)
    visibility = models.CharField(
        max_length=20,
        default="private",
        choices=(
            ("private", "Private"),
            ("workspace", "Workspace"),
            ("tenant", "Tenant"),
        ),
    )
    config = models.JSONField(
        default=dict,
        help_text="Dashboard layout config (grid rows, columns, gap…)",
    )
    sort_order = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "vis_dashboard_configuration"
        ordering = ("tenant", "sort_order", "name")

    def __str__(self) -> str:
        return f"Dashboard: {self.name}"


class DashboardWidget(
    UUIDModel,
    TenantScopedModel,
    TimeStampedModel,
):
    """A widget placement within a dashboard."""

    dashboard = models.ForeignKey(
        DashboardConfiguration,
        on_delete=models.CASCADE,
        related_name="widgets",
    )
    widget_type = models.CharField(max_length=100)
    title_key = models.CharField(max_length=255)
    row_index = models.PositiveIntegerField(default=0)
    col_span = models.PositiveIntegerField(default=3)
    sort_order = models.PositiveIntegerField(default=0)
    config = models.JSONField(
        default=dict,
        help_text="Widget-specific configuration",
    )

    class Meta:
        db_table = "vis_dashboard_widget"
        ordering = ("dashboard", "row_index", "sort_order")

    def __str__(self) -> str:
        return f"Widget: {self.widget_type} @ {self.dashboard.name}"


class ChartConfiguration(
    UUIDModel,
    TenantScopedModel,
    AuditedModel,
    SoftDeleteModel,
    TimeStampedModel,
):
    """A chart definition backed by an entity's data."""

    name = models.CharField(max_length=255)
    entity_name = models.CharField(max_length=255)
    chart_type = models.CharField(
        max_length=50,
        help_text="Chart kind: bar, line, pie, donut, area, scatter, radar, funnel, heatmap",
    )
    config = models.JSONField(
        default=dict,
        help_text="Chart configuration: x_axis, y_axis, group_by, aggregation, colors…",
    )
    is_default = models.BooleanField(default=False)
    visibility = models.CharField(
        max_length=20,
        default="private",
        choices=(
            ("private", "Private"),
            ("workspace", "Workspace"),
            ("tenant", "Tenant"),
        ),
    )

    class Meta:
        db_table = "vis_chart_configuration"
        ordering = ("entity_name", "name")

    def __str__(self) -> str:
        return f"Chart: {self.name} ({self.chart_type})"


class ViewGrouping(
    UUIDModel,
    TenantScopedModel,
    TimeStampedModel,
):
    """Grouping configuration for board/kanban views."""

    view = models.ForeignKey(
        ViewConfiguration,
        on_delete=models.CASCADE,
        related_name="groupings",
    )
    field_name = models.CharField(max_length=255)
    label_key = models.CharField(max_length=255, default="")
    color = models.CharField(max_length=50, default="")
    sort_order = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "vis_view_grouping"
        ordering = ("view", "sort_order")

    def __str__(self) -> str:
        return f"Grouping: {self.field_name} for {self.view.name}"
