"""Add fact tables

Revision ID: 7e65d4230d6b
Revises: bfaa66d237cf
Create Date: 2026-01-15 13:31:01.584061

"""

from typing import Sequence, Union

import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "7e65d4230d6b"
down_revision: Union[str, None] = "bfaa66d237cf"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        "fact_measurement",
        sa.Column("id", sa.BigInteger(), nullable=False),
        sa.Column("tenant", sa.UUID(), nullable=False),
        sa.Column("device_id", sa.Integer(), nullable=False),
        sa.Column("measured_ts", sa.DateTime(), nullable=False),
        sa.Column("date_id", sa.Integer(), nullable=True),
        sa.Column("value", sa.Float(), nullable=False),
        sa.Column("quality", sa.SmallInteger(), nullable=True),
        sa.Column("flags", sa.Integer(), nullable=True),
        sa.Column("created_ts", sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(["date_id"], ["dim_date.date_id"], ondelete="SET NULL"),
        sa.ForeignKeyConstraint(["device_id"], ["dim_device.id"], ondelete="RESTRICT"),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint(
            "tenant", "device_id", "measured_ts", name="uq_measurement_device_ts"
        ),
    )
    op.create_index(
        "idx_measurement_date", "fact_measurement", ["date_id"], unique=False
    )
    op.create_index(
        "idx_measurement_device_ts",
        "fact_measurement",
        ["device_id", "measured_ts"],
        unique=False,
    )
    op.create_index(
        "idx_measurement_tenant_ts",
        "fact_measurement",
        ["tenant", "measured_ts"],
        unique=False,
    )
    op.create_index(
        op.f("ix_fact_measurement_device_id"),
        "fact_measurement",
        ["device_id"],
        unique=False,
    )
    op.create_index(
        op.f("ix_fact_measurement_measured_ts"),
        "fact_measurement",
        ["measured_ts"],
        unique=False,
    )
    op.create_index(
        op.f("ix_fact_measurement_tenant"), "fact_measurement", ["tenant"], unique=False
    )
    op.create_table(
        "fact_state",
        sa.Column("id", sa.BigInteger(), nullable=False),
        sa.Column("tenant", sa.UUID(), nullable=False),
        sa.Column("device_id", sa.Integer(), nullable=False),
        sa.Column("state_ts", sa.DateTime(), nullable=False),
        sa.Column(
            "state_data", postgresql.JSONB(astext_type=sa.Text()), nullable=False
        ),
        sa.Column("numeric_value", sa.Float(), nullable=True),
        sa.Column("boolean_value", sa.Boolean(), nullable=True),
        sa.Column("text_value", sa.Text(), nullable=True),
        sa.Column("created_ts", sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(["device_id"], ["dim_device.id"], ondelete="RESTRICT"),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint(
            "tenant", "device_id", "state_ts", name="uq_state_device_ts"
        ),
    )
    op.create_index(
        "idx_state_data_gin",
        "fact_state",
        ["state_data"],
        unique=False,
        postgresql_using="gin",
    )
    op.create_index(
        "idx_state_device_ts", "fact_state", ["device_id", "state_ts"], unique=False
    )
    op.create_index(
        "idx_state_numeric_value",
        "fact_state",
        ["device_id", "state_ts"],
        unique=False,
        postgresql_where=sa.text("numeric_value IS NOT NULL"),
    )
    op.create_index(
        "idx_state_tenant_ts", "fact_state", ["tenant", "state_ts"], unique=False
    )
    op.create_index(
        op.f("ix_fact_state_device_id"), "fact_state", ["device_id"], unique=False
    )
    op.create_index(
        op.f("ix_fact_state_state_ts"), "fact_state", ["state_ts"], unique=False
    )
    op.create_index(
        op.f("ix_fact_state_tenant"), "fact_state", ["tenant"], unique=False
    )
    op.create_table(
        "fact_usage",
        sa.Column("id", sa.BigInteger(), nullable=False),
        sa.Column("tenant", sa.UUID(), nullable=False),
        sa.Column("device_id", sa.Integer(), nullable=False),
        sa.Column("date_id", sa.Integer(), nullable=True),
        sa.Column("period_type", sa.Text(), nullable=False),
        sa.Column("start_ts", sa.DateTime(), nullable=False),
        sa.Column("end_ts", sa.DateTime(), nullable=False),
        sa.Column("start_value", sa.Float(), nullable=True),
        sa.Column("end_value", sa.Float(), nullable=True),
        sa.Column("consumption", sa.Float(), nullable=False),
        sa.Column("price_per_unit", sa.Float(), nullable=True),
        sa.Column("total_cost", sa.Float(), nullable=True),
        sa.Column("currency", sa.Text(), nullable=True),
        sa.Column("calculation_ts", sa.DateTime(), nullable=True),
        sa.Column("quality_score", sa.SmallInteger(), nullable=True),
        sa.Column("created_ts", sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(["date_id"], ["dim_date.date_id"], ondelete="SET NULL"),
        sa.ForeignKeyConstraint(["device_id"], ["dim_device.id"], ondelete="RESTRICT"),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint(
            "tenant",
            "device_id",
            "period_type",
            "start_ts",
            name="uq_usage_device_period",
        ),
    )
    op.create_index(
        "idx_usage_cost",
        "fact_usage",
        ["tenant", "start_ts"],
        unique=False,
        postgresql_where=sa.text("total_cost IS NOT NULL"),
    )
    op.create_index("idx_usage_date", "fact_usage", ["date_id"], unique=False)
    op.create_index(
        "idx_usage_device_period", "fact_usage", ["device_id", "start_ts"], unique=False
    )
    op.create_index(
        "idx_usage_tenant_period",
        "fact_usage",
        ["tenant", "period_type", "start_ts"],
        unique=False,
    )
    op.create_index(
        op.f("ix_fact_usage_device_id"), "fact_usage", ["device_id"], unique=False
    )
    op.create_index(
        op.f("ix_fact_usage_period_type"), "fact_usage", ["period_type"], unique=False
    )
    op.create_index(
        op.f("ix_fact_usage_start_ts"), "fact_usage", ["start_ts"], unique=False
    )
    op.create_index(
        op.f("ix_fact_usage_tenant"), "fact_usage", ["tenant"], unique=False
    )
    op.alter_column(
        "measurement_raw", "is_processed", existing_type=sa.BOOLEAN(), nullable=False
    )
    op.create_index(
        op.f("ix_measurement_raw_is_processed"),
        "measurement_raw",
        ["is_processed"],
        unique=False,
    )
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index(op.f("ix_measurement_raw_is_processed"), table_name="measurement_raw")
    op.alter_column(
        "measurement_raw", "is_processed", existing_type=sa.BOOLEAN(), nullable=True
    )
    op.drop_index(op.f("ix_fact_usage_tenant"), table_name="fact_usage")
    op.drop_index(op.f("ix_fact_usage_start_ts"), table_name="fact_usage")
    op.drop_index(op.f("ix_fact_usage_period_type"), table_name="fact_usage")
    op.drop_index(op.f("ix_fact_usage_device_id"), table_name="fact_usage")
    op.drop_index("idx_usage_tenant_period", table_name="fact_usage")
    op.drop_index("idx_usage_device_period", table_name="fact_usage")
    op.drop_index("idx_usage_date", table_name="fact_usage")
    op.drop_index(
        "idx_usage_cost",
        table_name="fact_usage",
        postgresql_where=sa.text("total_cost IS NOT NULL"),
    )
    op.drop_table("fact_usage")
    op.drop_index(op.f("ix_fact_state_tenant"), table_name="fact_state")
    op.drop_index(op.f("ix_fact_state_state_ts"), table_name="fact_state")
    op.drop_index(op.f("ix_fact_state_device_id"), table_name="fact_state")
    op.drop_index("idx_state_tenant_ts", table_name="fact_state")
    op.drop_index(
        "idx_state_numeric_value",
        table_name="fact_state",
        postgresql_where=sa.text("numeric_value IS NOT NULL"),
    )
    op.drop_index("idx_state_device_ts", table_name="fact_state")
    op.drop_index("idx_state_data_gin", table_name="fact_state", postgresql_using="gin")
    op.drop_table("fact_state")
    op.drop_index(op.f("ix_fact_measurement_tenant"), table_name="fact_measurement")
    op.drop_index(
        op.f("ix_fact_measurement_measured_ts"), table_name="fact_measurement"
    )
    op.drop_index(op.f("ix_fact_measurement_device_id"), table_name="fact_measurement")
    op.drop_index("idx_measurement_tenant_ts", table_name="fact_measurement")
    op.drop_index("idx_measurement_device_ts", table_name="fact_measurement")
    op.drop_index("idx_measurement_date", table_name="fact_measurement")
    op.drop_table("fact_measurement")
    # ### end Alembic commands ###
