"""Checkpoint C2: règles, occurrences et tournées de relevés."""

from alembic import op
import sqlalchemy as sa


revision = "o0d1e2f3g4h5"
down_revision = "n9c0d1e2f3g4"
branch_labels = None
depends_on = None


def upgrade():
    op.create_table(
        "meter_reading_schedules",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column("meter_id", sa.Integer(), nullable=False),
        sa.Column("is_active", sa.Boolean(), nullable=False, server_default="1"),
        sa.Column("frequency", sa.String(30), nullable=False),
        sa.Column("reference_date", sa.Date(), nullable=False),
        sa.Column("target_time", sa.Time(), nullable=True),
        sa.Column("duration_minutes", sa.Integer(), nullable=False, server_default="5"),
        sa.Column("assigned_to_id", sa.Integer(), nullable=True),
        sa.Column("closed_day_policy", sa.String(30), nullable=False, server_default="PREVIOUS_WORKING_DAY"),
        sa.Column("calendar_scope", sa.String(20), nullable=False, server_default="school"),
        sa.Column("fixed_month", sa.Integer(), nullable=True),
        sa.Column("fixed_day", sa.Integer(), nullable=True),
        sa.Column("created_at", sa.DateTime(), nullable=False),
        sa.Column("updated_at", sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(["meter_id"], ["meters.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(["assigned_to_id"], ["users.id"], ondelete="SET NULL"),
        sa.UniqueConstraint("meter_id", name="uq_meter_reading_schedule_meter"),
        sa.CheckConstraint("frequency in ('WEEKLY', 'MONTHLY', 'SEMI_ANNUAL', 'ANNUAL', 'FIXED_ANNUAL_DATE')", name="ck_meter_reading_schedule_frequency"),
    )
    op.create_index("ix_meter_reading_schedules_meter_id", "meter_reading_schedules", ["meter_id"])
    op.create_index("ix_meter_reading_schedules_assigned_to_id", "meter_reading_schedules", ["assigned_to_id"])

    op.create_table(
        "meter_reading_rounds",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column("name", sa.String(255), nullable=False),
        sa.Column("is_active", sa.Boolean(), nullable=False, server_default="1"),
        sa.Column("default_assigned_to_id", sa.Integer(), nullable=True),
        sa.Column("estimated_duration_minutes", sa.Integer(), nullable=True),
        sa.Column("created_at", sa.DateTime(), nullable=False),
        sa.Column("updated_at", sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(["default_assigned_to_id"], ["users.id"], ondelete="SET NULL"),
    )
    op.create_index("ix_meter_reading_rounds_default_assigned_to_id", "meter_reading_rounds", ["default_assigned_to_id"])

    op.create_table(
        "meter_reading_round_members",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column("round_id", sa.Integer(), nullable=False),
        sa.Column("schedule_id", sa.Integer(), nullable=False),
        sa.Column("position", sa.Integer(), nullable=False),
        sa.ForeignKeyConstraint(["round_id"], ["meter_reading_rounds.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(["schedule_id"], ["meter_reading_schedules.id"], ondelete="CASCADE"),
        sa.UniqueConstraint("round_id", "schedule_id", name="uq_meter_round_schedule"),
        sa.UniqueConstraint("round_id", "position", name="uq_meter_round_position"),
    )
    op.create_index("ix_meter_reading_round_members_round_id", "meter_reading_round_members", ["round_id"])
    op.create_index("ix_meter_reading_round_members_schedule_id", "meter_reading_round_members", ["schedule_id"])

    op.create_table(
        "meter_reading_round_occurrences",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column("round_id", sa.Integer(), nullable=False),
        sa.Column("operational_date", sa.Date(), nullable=False),
        sa.Column("status", sa.String(30), nullable=False, server_default="À FAIRE"),
        sa.Column("created_at", sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(["round_id"], ["meter_reading_rounds.id"], ondelete="CASCADE"),
        sa.UniqueConstraint("round_id", "operational_date", name="uq_meter_round_occurrence_date"),
    )
    op.create_index("ix_meter_reading_round_occurrences_round_id", "meter_reading_round_occurrences", ["round_id"])
    op.create_index("ix_meter_reading_round_occurrences_operational_date", "meter_reading_round_occurrences", ["operational_date"])

    op.create_table(
        "meter_reading_occurrences",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column("schedule_id", sa.Integer(), nullable=False),
        sa.Column("target_date", sa.Date(), nullable=False),
        sa.Column("operational_date", sa.Date(), nullable=False),
        sa.Column("status", sa.String(30), nullable=False, server_default="À FAIRE"),
        sa.Column("assigned_to_id", sa.Integer(), nullable=True),
        sa.Column("meter_reading_id", sa.Integer(), nullable=True),
        sa.Column("round_occurrence_id", sa.Integer(), nullable=True),
        sa.Column("processed_by_id", sa.Integer(), nullable=True),
        sa.Column("processed_at", sa.DateTime(), nullable=True),
        sa.Column("no_reading_reason", sa.String(40), nullable=True),
        sa.Column("comment", sa.Text(), nullable=True),
        sa.Column("created_at", sa.DateTime(), nullable=False),
        sa.Column("updated_at", sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(["schedule_id"], ["meter_reading_schedules.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(["assigned_to_id"], ["users.id"], ondelete="SET NULL"),
        sa.ForeignKeyConstraint(["meter_reading_id"], ["meter_readings.id"], ondelete="SET NULL"),
        sa.ForeignKeyConstraint(["round_occurrence_id"], ["meter_reading_round_occurrences.id"], ondelete="SET NULL"),
        sa.ForeignKeyConstraint(["processed_by_id"], ["users.id"], ondelete="SET NULL"),
        sa.UniqueConstraint("schedule_id", "target_date", name="uq_meter_reading_occurrence_target"),
    )
    for name, column in (
        ("schedule_id", "schedule_id"), ("target_date", "target_date"),
        ("operational_date", "operational_date"), ("assigned_to_id", "assigned_to_id"),
        ("meter_reading_id", "meter_reading_id"), ("round_occurrence_id", "round_occurrence_id"),
        ("processed_by_id", "processed_by_id"),
    ):
        op.create_index(f"ix_meter_reading_occurrences_{name}", "meter_reading_occurrences", [column])


def downgrade():
    for name in (
        "ix_meter_reading_occurrences_processed_by_id", "ix_meter_reading_occurrences_round_occurrence_id",
        "ix_meter_reading_occurrences_meter_reading_id", "ix_meter_reading_occurrences_assigned_to_id",
        "ix_meter_reading_occurrences_operational_date", "ix_meter_reading_occurrences_target_date",
        "ix_meter_reading_occurrences_schedule_id",
    ):
        op.drop_index(name, table_name="meter_reading_occurrences")
    op.drop_table("meter_reading_occurrences")
    op.drop_index("ix_meter_reading_round_occurrences_operational_date", table_name="meter_reading_round_occurrences")
    op.drop_index("ix_meter_reading_round_occurrences_round_id", table_name="meter_reading_round_occurrences")
    op.drop_table("meter_reading_round_occurrences")
    op.drop_index("ix_meter_reading_round_members_schedule_id", table_name="meter_reading_round_members")
    op.drop_index("ix_meter_reading_round_members_round_id", table_name="meter_reading_round_members")
    op.drop_table("meter_reading_round_members")
    op.drop_index("ix_meter_reading_rounds_default_assigned_to_id", table_name="meter_reading_rounds")
    op.drop_table("meter_reading_rounds")
    op.drop_index("ix_meter_reading_schedules_assigned_to_id", table_name="meter_reading_schedules")
    op.drop_index("ix_meter_reading_schedules_meter_id", table_name="meter_reading_schedules")
    op.drop_table("meter_reading_schedules")
