"""create repairs module

Revision ID: c8e2f1a9b704
Revises: b6f3d8c1a920
Create Date: 2026-07-04 11:00:00.000000

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


revision: str = "c8e2f1a9b704"
down_revision: Union[str, Sequence[str], None] = "b6f3d8c1a920"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


REPAIR_PERMISSIONS = [
    ("repairs.read", "Reparaturen lesen", "Reparaturen anzeigen", "repairs"),
    ("repairs.create", "Reparaturen erstellen", "Reparaturen anlegen", "repairs"),
    ("repairs.update", "Reparaturen bearbeiten", "Reparaturen aktualisieren", "repairs"),
    ("repairs.delete", "Reparaturen löschen", "Reparaturen stornieren", "repairs"),
    ("repairs.status.update", "Reparaturstatus ändern", "Status von Reparaturen ändern", "repairs"),
    ("repairs.intake", "Reparatur-Intake", "Website-Reparaturanfragen übernehmen", "repairs"),
    ("repairs.assign", "Reparaturen zuweisen", "Reparaturen Benutzern zuweisen", "repairs"),
]

ROLE_PERMISSIONS = {
    "administrator": [permission[0] for permission in REPAIR_PERMISSIONS],
    "management": ["repairs.read", "repairs.create", "repairs.update", "repairs.status.update"],
    "technician": ["repairs.read", "repairs.update", "repairs.status.update"],
    "support": ["repairs.read", "repairs.create", "repairs.update", "repairs.status.update", "repairs.intake"],
}


def upgrade() -> None:
    op.create_table(
        "repairs",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("repair_number", sa.String(length=20), nullable=False),
        sa.Column("customer_id", sa.Integer(), nullable=True),
        sa.Column("contact_id", sa.Integer(), nullable=True),
        sa.Column("status", sa.String(length=50), nullable=False),
        sa.Column("priority", sa.String(length=30), nullable=False),
        sa.Column("source", sa.String(length=50), nullable=False),
        sa.Column("source_reference", sa.String(length=120), nullable=True),
        sa.Column("customer_name", sa.String(length=255), nullable=False),
        sa.Column("customer_email", sa.String(length=255), server_default="", nullable=False),
        sa.Column("customer_phone", sa.String(length=80), server_default="", nullable=False),
        sa.Column("device_manufacturer", sa.String(length=160), nullable=False),
        sa.Column("device_model", sa.String(length=160), nullable=False),
        sa.Column("device_serial_number", sa.String(length=160), nullable=True),
        sa.Column("device_type", sa.String(length=120), server_default="", nullable=False),
        sa.Column("accessories", sa.Text(), server_default="", nullable=False),
        sa.Column("fault_description", sa.Text(), nullable=False),
        sa.Column("previous_work", sa.Text(), server_default="", nullable=False),
        sa.Column("device_opened", sa.Boolean(), server_default="false", nullable=False),
        sa.Column("intake_notes", sa.Text(), server_default="", nullable=False),
        sa.Column("diagnosis_notes", sa.Text(), server_default="", nullable=False),
        sa.Column("repair_notes", sa.Text(), server_default="", nullable=False),
        sa.Column("estimate_notes", sa.Text(), server_default="", nullable=False),
        sa.Column("estimated_cost_cents", sa.Integer(), nullable=True),
        sa.Column("approved_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("completed_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.CheckConstraint("status in ('new','accepted','diagnosis','estimate','waiting_for_customer','approved','repair','final_test','ready_for_pickup','shipped','completed','cancelled')", name="ck_repairs_status"),
        sa.CheckConstraint("priority in ('low','normal','high','urgent')", name="ck_repairs_priority"),
        sa.CheckConstraint("source in ('manual','website','customer_portal','email','phone')", name="ck_repairs_source"),
        sa.ForeignKeyConstraint(["contact_id"], ["customer_contacts.id"], ondelete="SET NULL"),
        sa.ForeignKeyConstraint(["customer_id"], ["customers.id"], ondelete="SET NULL"),
        sa.PrimaryKeyConstraint("id"),
        sa.UniqueConstraint("repair_number"),
    )
    op.create_index(op.f("ix_repairs_contact_id"), "repairs", ["contact_id"], unique=False)
    op.create_index(op.f("ix_repairs_customer_id"), "repairs", ["customer_id"], unique=False)
    op.create_index(op.f("ix_repairs_customer_name"), "repairs", ["customer_name"], unique=False)
    op.create_index(op.f("ix_repairs_device_manufacturer"), "repairs", ["device_manufacturer"], unique=False)
    op.create_index(op.f("ix_repairs_device_model"), "repairs", ["device_model"], unique=False)
    op.create_index(op.f("ix_repairs_priority"), "repairs", ["priority"], unique=False)
    op.create_index(op.f("ix_repairs_repair_number"), "repairs", ["repair_number"], unique=True)
    op.create_index(op.f("ix_repairs_source"), "repairs", ["source"], unique=False)
    op.create_index(op.f("ix_repairs_source_reference"), "repairs", ["source_reference"], unique=False)
    op.create_index(op.f("ix_repairs_status"), "repairs", ["status"], unique=False)

    op.create_table(
        "repair_status_history",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("repair_id", sa.Integer(), nullable=False),
        sa.Column("old_status", sa.String(length=50), nullable=True),
        sa.Column("new_status", sa.String(length=50), nullable=False),
        sa.Column("note", sa.Text(), nullable=True),
        sa.Column("actor_user_id", sa.Integer(), nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.ForeignKeyConstraint(["actor_user_id"], ["users.id"], ondelete="SET NULL"),
        sa.ForeignKeyConstraint(["repair_id"], ["repairs.id"], ondelete="CASCADE"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(op.f("ix_repair_status_history_actor_user_id"), "repair_status_history", ["actor_user_id"], unique=False)
    op.create_index(op.f("ix_repair_status_history_new_status"), "repair_status_history", ["new_status"], unique=False)
    op.create_index(op.f("ix_repair_status_history_repair_id"), "repair_status_history", ["repair_id"], unique=False)

    op.create_table(
        "repair_intake_events",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("repair_id", sa.Integer(), nullable=True),
        sa.Column("external_source", sa.String(length=80), nullable=False),
        sa.Column("external_reference", sa.String(length=160), nullable=True),
        sa.Column("payload", sa.JSON(), nullable=False),
        sa.Column("status", sa.String(length=50), nullable=False),
        sa.Column("error_message", sa.Text(), nullable=True),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("processed_at", sa.DateTime(timezone=True), nullable=True),
        sa.ForeignKeyConstraint(["repair_id"], ["repairs.id"], ondelete="SET NULL"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(op.f("ix_repair_intake_events_external_reference"), "repair_intake_events", ["external_reference"], unique=False)
    op.create_index(op.f("ix_repair_intake_events_external_source"), "repair_intake_events", ["external_source"], unique=False)
    op.create_index(op.f("ix_repair_intake_events_repair_id"), "repair_intake_events", ["repair_id"], unique=False)
    op.create_index(op.f("ix_repair_intake_events_status"), "repair_intake_events", ["status"], unique=False)

    op.create_table(
        "repair_documents",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("repair_id", sa.Integer(), nullable=False),
        sa.Column("file_id", sa.Integer(), nullable=True),
        sa.Column("storage_path", sa.String(length=500), nullable=True),
        sa.Column("title", sa.String(length=255), nullable=False),
        sa.Column("document_type", sa.String(length=80), nullable=False),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.ForeignKeyConstraint(["repair_id"], ["repairs.id"], ondelete="CASCADE"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(op.f("ix_repair_documents_document_type"), "repair_documents", ["document_type"], unique=False)
    op.create_index(op.f("ix_repair_documents_repair_id"), "repair_documents", ["repair_id"], unique=False)

    for name, display_name, description, module in REPAIR_PERMISSIONS:
        op.execute(
            sa.text(
                """
                insert into permissions (name, display_name, description, module)
                values (:name, :display_name, :description, :module)
                on conflict (name) do update set
                    display_name = excluded.display_name,
                    description = excluded.description,
                    module = excluded.module
                """
            ).bindparams(name=name, display_name=display_name, description=description, module=module)
        )

    for role_name, permissions in ROLE_PERMISSIONS.items():
        for permission_name in permissions:
            op.execute(
                sa.text(
                    """
                    insert into role_permissions (role_id, permission_id)
                    select roles.id, permissions.id
                    from roles, permissions
                    where roles.name = :role_name and permissions.name = :permission_name
                    on conflict do nothing
                    """
                ).bindparams(role_name=role_name, permission_name=permission_name)
            )


def downgrade() -> None:
    for permission_name, *_ in REPAIR_PERMISSIONS:
        op.execute(
            sa.text(
                """
                delete from role_permissions
                using permissions
                where role_permissions.permission_id = permissions.id
                  and permissions.name = :permission_name
                """
            ).bindparams(permission_name=permission_name)
        )
        op.execute(sa.text("delete from permissions where name = :name").bindparams(name=permission_name))

    op.drop_index(op.f("ix_repair_documents_repair_id"), table_name="repair_documents")
    op.drop_index(op.f("ix_repair_documents_document_type"), table_name="repair_documents")
    op.drop_table("repair_documents")
    op.drop_index(op.f("ix_repair_intake_events_status"), table_name="repair_intake_events")
    op.drop_index(op.f("ix_repair_intake_events_repair_id"), table_name="repair_intake_events")
    op.drop_index(op.f("ix_repair_intake_events_external_source"), table_name="repair_intake_events")
    op.drop_index(op.f("ix_repair_intake_events_external_reference"), table_name="repair_intake_events")
    op.drop_table("repair_intake_events")
    op.drop_index(op.f("ix_repair_status_history_repair_id"), table_name="repair_status_history")
    op.drop_index(op.f("ix_repair_status_history_new_status"), table_name="repair_status_history")
    op.drop_index(op.f("ix_repair_status_history_actor_user_id"), table_name="repair_status_history")
    op.drop_table("repair_status_history")
    op.drop_index(op.f("ix_repairs_status"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_source_reference"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_source"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_repair_number"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_priority"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_device_model"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_device_manufacturer"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_customer_name"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_customer_id"), table_name="repairs")
    op.drop_index(op.f("ix_repairs_contact_id"), table_name="repairs")
    op.drop_table("repairs")
