"""Database models for user-owned factory dashboards.

Dashboard definitions are persisted in the database. Widget placement is not:
the read-only live viewer stores its Gridstack layout in browser localStorage so
each browser can arrange the same user's widgets independently.
"""

import uuid
from datetime import datetime

from extensions import db


class Dashboard(db.Model):
    __tablename__ = "dashboards"

    id = db.Column(db.Integer, primary_key=True)

    # Intentionally not declared as a ForeignKey until the application's user
    # table name is confirmed. API queries always scope by current_user().id.
    user_id = db.Column(db.Integer, nullable=False, index=True)

    name = db.Column(db.String(128), nullable=False)
    is_favorite = db.Column(db.Boolean, nullable=False, default=False)

    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    updated_at = db.Column(
        db.DateTime,
        nullable=False,
        default=datetime.utcnow,
        onupdate=datetime.utcnow,
    )

    widgets = db.relationship(
        "DashboardWidget",
        back_populates="dashboard",
        cascade="all, delete-orphan",
        lazy=True,
        order_by="DashboardWidget.created_at.asc()",
    )

    __table_args__ = (
        db.Index("ix_dashboards_user_favorite", "user_id", "is_favorite"),
    )


class DashboardWidget(db.Model):
    __tablename__ = "dashboard_widgets"

    id = db.Column(
        db.String(36),
        primary_key=True,
        default=lambda: str(uuid.uuid4()),
    )

    dashboard_id = db.Column(
        db.Integer,
        db.ForeignKey("dashboards.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )

    # Parameter widgets use parameter_id. Static markdown widgets do not need
    # a machine or parameter. Machine-summary widgets use machine_id directly.
    parameter_id = db.Column(
        db.String(36),
        db.ForeignKey("parameters.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    machine_id = db.Column(
        db.Integer,
        db.ForeignKey("machines.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    # Supported values: graph, text, machine, markdown.
    widget_type = db.Column(db.String(20), nullable=False)

    title = db.Column(db.String(160), nullable=True)
    decimal_precision = db.Column(db.Integer, nullable=False, default=3)
    markdown_content = db.Column(db.Text, nullable=True)

    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    updated_at = db.Column(
        db.DateTime,
        nullable=False,
        default=datetime.utcnow,
        onupdate=datetime.utcnow,
    )

    dashboard = db.relationship("Dashboard", back_populates="widgets")

    # The backref lets normal ORM parameter deletes cascade to widgets. The
    # existing machine-delete endpoint uses bulk deletes, so it also performs
    # explicit dashboard-widget cleanup.
    parameter = db.relationship(
        "Parameter",
        backref=db.backref("dashboard_widgets", cascade="all, delete-orphan"),
    )

    machine = db.relationship(
        "Machine",
        backref=db.backref("dashboard_widgets", cascade="all, delete-orphan"),
    )
