"""RLS completa su tutte le tabelle applicative + ruolo pechub_app

Revision ID: 0006
Revises: 0005
Create Date: 2026-03-19 00:00:00.000000

Aggiunge:
  - ENABLE ROW LEVEL SECURITY + policy USING (tenant_id = ...) su tutte le
    tabelle applicative che mancavano (attachments, send_jobs, archival_batches,
    archival_dips, labels, mailbox_permissions, virtual_boxes,
    notification_channels, notification_rules, notification_log, tenant_settings)
  - Crea il ruolo PostgreSQL applicativo 'pechub_app' (non-superuser) con
    GRANT SELECT/INSERT/UPDATE/DELETE su tutte le tabelle.
    Il ruolo viene usato dalla connessione applicativa (DATABASE_URL) mentre
    Alembic continua ad usare l'utente superuser (DATABASE_URL_SYNC).

Nota: la migrazione usa DO $$ BEGIN ... EXCEPTION WHEN ... END $$ per
rendere idempotente la creazione del ruolo e delle policy.
"""

from alembic import op

revision = "0006"
down_revision = "0005"
branch_labels = None
depends_on = None

# Tabelle con tenant_id che devono avere RLS (escluse quelle già gestite in 0001)
_RLS_TABLES = [
    "attachments",
    "send_jobs",
    "archival_batches",
    "archival_dips",
    "labels",
    "mailbox_permissions",
    "virtual_boxes",
    "notification_channels",
    "notification_rules",
    "notification_log",
    "tenant_settings",
]

# Tutte le tabelle su cui pechub_app ha SELECT/INSERT/UPDATE/DELETE
_ALL_APP_TABLES = [
    "tenants",
    "users",
    "refresh_tokens",
    "mailboxes",
    "messages",
    "attachments",
    "send_jobs",
    "archival_batches",
    "archival_batch_messages",
    "archival_dips",
    "labels",
    "message_labels",
    "mailbox_permissions",
    "virtual_boxes",
    "virtual_box_rules",
    "virtual_box_assignments",
    "virtual_box_mailboxes",
    "notification_channels",
    "notification_rules",
    "notification_log",
    "audit_log",
    "tenant_settings",
]


def upgrade() -> None:
    # ── 1. Abilita RLS + policy su tabelle mancanti ───────────────────────────
    for table in _RLS_TABLES:
        op.execute(f"ALTER TABLE {table} ENABLE ROW LEVEL SECURITY")
        # Politica idempotente: elimina la policy se esiste e la ricrea
        op.execute(
            f"""
            DO $$
            BEGIN
                -- Elimina policy esistente (se presente da un run precedente)
                DROP POLICY IF EXISTS {table}_tenant_isolation ON {table};
                -- Crea la nuova policy
                CREATE POLICY {table}_tenant_isolation ON {table}
                USING (
                    tenant_id = NULLIF(
                        current_setting('app.current_tenant_id', TRUE), ''
                    )::UUID
                );
            END
            $$;
            """
        )

    # ── 2. Crea ruolo applicativo pechub_app (non-superuser) ──────────────────
    op.execute(
        """
        DO $$
        BEGIN
            IF NOT EXISTS (
                SELECT 1 FROM pg_roles WHERE rolname = 'pechub_app'
            ) THEN
                CREATE USER pechub_app WITH PASSWORD 'pechub_app_password'
                    NOSUPERUSER NOCREATEDB NOCREATEROLE;
                RAISE NOTICE 'Ruolo pechub_app creato';
            ELSE
                RAISE NOTICE 'Ruolo pechub_app già esistente – skip';
            END IF;
        END
        $$;
        """
    )

    # ── 3. Permessi al ruolo applicativo ──────────────────────────────────────
    op.execute("GRANT CONNECT ON DATABASE pechub TO pechub_app")
    op.execute("GRANT USAGE ON SCHEMA public TO pechub_app")

    for table in _ALL_APP_TABLES:
        op.execute(
            f"GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE {table} TO pechub_app"
        )

    # Sequenze (per BIGSERIAL come audit_log.id)
    op.execute("GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO pechub_app")

    # Default privileges: le tabelle create nelle migrazioni future ricevono
    # automaticamente i permessi per pechub_app
    op.execute(
        """
        ALTER DEFAULT PRIVILEGES FOR ROLE pechub IN SCHEMA public
        GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO pechub_app;
        """
    )
    op.execute(
        """
        ALTER DEFAULT PRIVILEGES FOR ROLE pechub IN SCHEMA public
        GRANT USAGE, SELECT ON SEQUENCES TO pechub_app;
        """
    )


def downgrade() -> None:
    # Rimuovi policy e disabilita RLS
    for table in _RLS_TABLES:
        op.execute(
            f"DROP POLICY IF EXISTS {table}_tenant_isolation ON {table}"
        )
        op.execute(f"ALTER TABLE {table} DISABLE ROW LEVEL SECURITY")

    # Revoca permessi e rimuovi ruolo
    op.execute("REVOKE ALL ON ALL TABLES IN SCHEMA public FROM pechub_app")
    op.execute("REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM pechub_app")
    op.execute("REVOKE USAGE ON SCHEMA public FROM pechub_app")
    op.execute("REVOKE CONNECT ON DATABASE pechub FROM pechub_app")
    op.execute("DROP USER IF EXISTS pechub_app")
