"""add rbac

Revision ID: 7b2c9f4a0d31
Revises: 3f4c7b8d1e2a
Create Date: 2026-07-02 13:00:00.000000

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


revision: str = "7b2c9f4a0d31"
down_revision: Union[str, Sequence[str], None] = "3f4c7b8d1e2a"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


ROLES = [
    ("administrator", "Administrator", "Vollzugriff auf Olympus CRM"),
    ("management", "Management", "Lesender Zugriff auf operative Kernmodule"),
    ("sales", "Vertrieb", "Zugriff auf Kunden und Projekte"),
    ("technician", "Technik", "Zugriff auf Tickets und Projekte"),
    ("support", "Support", "Operativer Support-Zugriff"),
    ("warehouse", "Lager", "Zugriff auf lagernahe Prozesse"),
    ("guest", "Gast", "Minimaler Zugriff"),
]

PERMISSIONS = [
    ("users.read", "Benutzer lesen", "Benutzer anzeigen", "users"),
    ("users.create", "Benutzer erstellen", "Benutzer anlegen", "users"),
    ("users.update", "Benutzer bearbeiten", "Benutzer aktualisieren", "users"),
    ("users.delete", "Benutzer loeschen", "Benutzer entfernen", "users"),
    ("users.password.update", "Passwort aendern", "Benutzerpasswort aendern", "users"),
    ("roles.read", "Rollen lesen", "Rollen anzeigen", "roles"),
    ("roles.create", "Rollen erstellen", "Rollen anlegen", "roles"),
    ("roles.update", "Rollen bearbeiten", "Rollen aktualisieren", "roles"),
    ("roles.delete", "Rollen loeschen", "Rollen entfernen", "roles"),
    ("roles.assign", "Rollen zuweisen", "Berechtigungen Rollen zuweisen", "roles"),
    ("customers.read", "Kunden lesen", "Kunden anzeigen", "customers"),
    ("customers.create", "Kunden erstellen", "Kunden anlegen", "customers"),
    ("customers.update", "Kunden bearbeiten", "Kunden aktualisieren", "customers"),
    ("customers.delete", "Kunden loeschen", "Kunden entfernen", "customers"),
    ("projects.read", "Projekte lesen", "Projekte anzeigen", "projects"),
    ("projects.create", "Projekte erstellen", "Projekte anlegen", "projects"),
    ("projects.update", "Projekte bearbeiten", "Projekte aktualisieren", "projects"),
    ("projects.delete", "Projekte loeschen", "Projekte entfernen", "projects"),
    ("tickets.read", "Tickets lesen", "Tickets anzeigen", "tickets"),
    ("tickets.create", "Tickets erstellen", "Tickets anlegen", "tickets"),
    ("tickets.update", "Tickets bearbeiten", "Tickets aktualisieren", "tickets"),
    ("tickets.delete", "Tickets loeschen", "Tickets entfernen", "tickets"),
    ("dashboard.read", "Dashboard lesen", "Dashboard anzeigen", "dashboard"),
    ("system.settings.read", "Einstellungen lesen", "Systemeinstellungen anzeigen", "system"),
    ("system.settings.update", "Einstellungen bearbeiten", "Systemeinstellungen aktualisieren", "system"),
]


def upgrade() -> None:
    op.create_table(
        "roles",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("name", sa.String(length=80), nullable=False),
        sa.Column("display_name", sa.String(length=120), nullable=False),
        sa.Column("description", sa.String(length=500), server_default="", nullable=False),
        sa.Column("is_system", sa.Boolean(), server_default=sa.true(), nullable=False),
        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.PrimaryKeyConstraint("id"),
    )
    op.create_index(op.f("ix_roles_name"), "roles", ["name"], unique=True)

    op.create_table(
        "permissions",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("name", sa.String(length=120), nullable=False),
        sa.Column("display_name", sa.String(length=160), nullable=False),
        sa.Column("description", sa.String(length=500), server_default="", nullable=False),
        sa.Column("module", sa.String(length=80), nullable=False),
        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.PrimaryKeyConstraint("id"),
    )
    op.create_index(op.f("ix_permissions_module"), "permissions", ["module"], unique=False)
    op.create_index(op.f("ix_permissions_name"), "permissions", ["name"], unique=True)

    op.create_table(
        "role_permissions",
        sa.Column("role_id", sa.Integer(), nullable=False),
        sa.Column("permission_id", sa.Integer(), nullable=False),
        sa.ForeignKeyConstraint(["permission_id"], ["permissions.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(["role_id"], ["roles.id"], ondelete="CASCADE"),
        sa.PrimaryKeyConstraint("role_id", "permission_id"),
    )

    roles_table = sa.table(
        "roles",
        sa.column("name", sa.String),
        sa.column("display_name", sa.String),
        sa.column("description", sa.String),
        sa.column("is_system", sa.Boolean),
    )
    permissions_table = sa.table(
        "permissions",
        sa.column("name", sa.String),
        sa.column("display_name", sa.String),
        sa.column("description", sa.String),
        sa.column("module", sa.String),
    )

    op.bulk_insert(
        roles_table,
        [
            {
                "name": name,
                "display_name": display_name,
                "description": description,
                "is_system": True,
            }
            for name, display_name, description in ROLES
        ],
    )
    op.bulk_insert(
        permissions_table,
        [
            {
                "name": name,
                "display_name": display_name,
                "description": description,
                "module": module,
            }
            for name, display_name, description, module in PERMISSIONS
        ],
    )

    op.execute(
        """
        INSERT INTO role_permissions (role_id, permission_id)
        SELECT roles.id, permissions.id
        FROM roles
        CROSS JOIN permissions
        WHERE roles.name = 'administrator'
        """
    )
    op.execute(
        """
        INSERT INTO role_permissions (role_id, permission_id)
        SELECT roles.id, permissions.id
        FROM roles
        JOIN permissions ON permissions.name IN (
            'dashboard.read',
            'users.read',
            'customers.read',
            'projects.read',
            'tickets.read'
        )
        WHERE roles.name = 'management'
        """
    )
    op.execute(
        """
        INSERT INTO role_permissions (role_id, permission_id)
        SELECT roles.id, permissions.id
        FROM roles
        JOIN permissions ON permissions.name IN (
            'dashboard.read',
            'customers.read',
            'customers.create',
            'customers.update',
            'projects.read',
            'tickets.read'
        )
        WHERE roles.name = 'sales'
        """
    )
    op.execute(
        """
        INSERT INTO role_permissions (role_id, permission_id)
        SELECT roles.id, permissions.id
        FROM roles
        JOIN permissions ON permissions.name IN (
            'dashboard.read',
            'projects.read',
            'tickets.read',
            'tickets.create',
            'tickets.update'
        )
        WHERE roles.name = 'technician'
        """
    )
    op.execute(
        """
        INSERT INTO role_permissions (role_id, permission_id)
        SELECT roles.id, permissions.id
        FROM roles
        JOIN permissions ON permissions.name IN (
            'dashboard.read',
            'users.read',
            'customers.read',
            'tickets.read',
            'tickets.create',
            'tickets.update'
        )
        WHERE roles.name = 'support'
        """
    )
    op.execute(
        """
        INSERT INTO role_permissions (role_id, permission_id)
        SELECT roles.id, permissions.id
        FROM roles
        JOIN permissions ON permissions.name IN (
            'dashboard.read'
        )
        WHERE roles.name IN ('warehouse', 'guest')
        """
    )

    op.add_column("users", sa.Column("role_id", sa.Integer(), nullable=True))
    op.create_index(op.f("ix_users_role_id"), "users", ["role_id"], unique=False)
    op.create_foreign_key("fk_users_role_id_roles", "users", "roles", ["role_id"], ["id"])

    op.execute(
        """
        UPDATE users
        SET role_id = roles.id
        FROM roles
        WHERE roles.name = CASE
            WHEN users.role IN ('admin', 'administrator') THEN 'administrator'
            WHEN users.role IN ('manager', 'management') THEN 'management'
            WHEN users.role = 'sales' THEN 'sales'
            WHEN users.role IN ('technician', 'tech') THEN 'technician'
            WHEN users.role = 'warehouse' THEN 'warehouse'
            WHEN users.role = 'guest' THEN 'guest'
            ELSE 'support'
        END
        """
    )
    op.execute(
        """
        UPDATE users
        SET role_id = (SELECT id FROM roles WHERE name = 'administrator')
        WHERE id = (
            SELECT id
            FROM users
            ORDER BY id
            LIMIT 1
        )
        AND NOT EXISTS (
            SELECT 1
            FROM users
            JOIN roles ON users.role_id = roles.id
            WHERE roles.name = 'administrator'
        )
        """
    )
    op.alter_column("users", "role_id", existing_type=sa.Integer(), nullable=False)


def downgrade() -> None:
    op.drop_constraint("fk_users_role_id_roles", "users", type_="foreignkey")
    op.drop_index(op.f("ix_users_role_id"), table_name="users")
    op.drop_column("users", "role_id")
    op.drop_table("role_permissions")
    op.drop_index(op.f("ix_permissions_name"), table_name="permissions")
    op.drop_index(op.f("ix_permissions_module"), table_name="permissions")
    op.drop_table("permissions")
    op.drop_index(op.f("ix_roles_name"), table_name="roles")
    op.drop_table("roles")
