"""add energy pricing and DSMR metering tables

Revision ID: 20260623_11_energy_tables
Revises: 20260622_10_exposed_entities
Create Date: 2026-06-23 00:00:00.000000
"""

from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op


revision: str = "20260623_11_energy_tables"
down_revision: Union[str, None] = "20260622_10_exposed_entities"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # dsmr_reading — raw DSMR telegram blobs (10-second down-sampled).
    # No device table: single P1 smart meter; a ``source`` column can be added later
    # if a second meter is introduced.
    op.create_table(
        "dsmr_reading",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column("recorded_at", sa.DateTime(timezone=True), nullable=False),
        sa.Column("source_id", sa.Integer(), nullable=True),
        sa.Column("payload", sa.JSON(), nullable=False),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint("source_id", name="uq_dsmr_reading_source_id"),
    )
    op.create_index(
        "ix_dsmr_reading_recorded_at",
        "dsmr_reading",
        ["recorded_at"],
        unique=False,
    )

    # energy_contract — contract head (manual or tibber, one active at a time).
    op.create_table(
        "energy_contract",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column("name", sa.String(length=255), nullable=False),
        sa.Column("kind", sa.String(length=32), nullable=False),
        sa.Column("active", sa.Boolean(), nullable=False),
        sa.Column("currency", sa.String(length=8), nullable=False),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
        sa.PrimaryKeyConstraint("id"),
    )

    # energy_contract_version — versioned pricing values; append-only for auditability.
    # Must be created after energy_contract because of the FK dependency.
    op.create_table(
        "energy_contract_version",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column("contract_id", sa.Integer(), nullable=False),
        sa.Column("effective_from", sa.DateTime(timezone=True), nullable=False),
        sa.Column("effective_to", sa.DateTime(timezone=True), nullable=True),
        sa.Column("values", sa.JSON(), nullable=False),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
        sa.ForeignKeyConstraint(
            ["contract_id"],
            ["energy_contract.id"],
            ondelete="RESTRICT",
        ),
        sa.PrimaryKeyConstraint("id"),
    )

    # tibber_price — cached Tibber 15-minute spot prices (immutable once fetched).
    op.create_table(
        "tibber_price",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column("starts_at", sa.DateTime(timezone=True), nullable=False),
        sa.Column("resolution", sa.String(length=32), nullable=False),
        sa.Column("energy", sa.Float(), nullable=False),
        sa.Column("tax", sa.Float(), nullable=False),
        sa.Column("total", sa.Float(), nullable=False),
        sa.Column("level", sa.String(length=32), nullable=True),
        sa.Column("currency", sa.String(length=8), nullable=False),
        sa.Column("fetched_at", sa.DateTime(timezone=True), nullable=False),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint("starts_at", name="uq_tibber_price_starts_at"),
    )

    # energy_cost_period — computed 15-minute billing periods (immutable snapshot).
    # Must be created after energy_contract_version because of the FK dependency.
    op.create_table(
        "energy_cost_period",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column("period_start", sa.DateTime(timezone=True), nullable=False),
        sa.Column("d1_kwh", sa.Float(), nullable=False),
        sa.Column("d2_kwh", sa.Float(), nullable=False),
        sa.Column("r1_kwh", sa.Float(), nullable=False),
        sa.Column("r2_kwh", sa.Float(), nullable=False),
        sa.Column("import_cost", sa.Float(), nullable=False),
        sa.Column("export_revenue", sa.Float(), nullable=False),
        sa.Column("net_cost", sa.Float(), nullable=False),
        sa.Column("currency", sa.String(length=8), nullable=False),
        sa.Column("pricing", sa.JSON(), nullable=False),
        sa.Column("contract_version_id", sa.Integer(), nullable=True),
        sa.Column("degraded", sa.Boolean(), nullable=False),
        sa.Column("computed_at", sa.DateTime(timezone=True), nullable=False),
        sa.ForeignKeyConstraint(
            ["contract_version_id"],
            ["energy_contract_version.id"],
            ondelete="RESTRICT",
        ),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint("period_start", name="uq_energy_cost_period_period_start"),
    )


def downgrade() -> None:
    # Drop tables in reverse dependency order: tables with FKs first.

    # energy_cost_period has a FK to energy_contract_version — drop it first.
    op.drop_table("energy_cost_period")

    # tibber_price has no FK dependencies on our new tables.
    op.drop_table("tibber_price")

    # energy_contract_version has a FK to energy_contract — drop it before energy_contract.
    op.drop_table("energy_contract_version")

    # energy_contract has no FK dependencies on our new tables.
    op.drop_table("energy_contract")

    # dsmr_reading has no FK dependencies.
    op.drop_index("ix_dsmr_reading_recorded_at", table_name="dsmr_reading")
    op.drop_table("dsmr_reading")
