"""allow only operation-guarded alias restoration during rollback

Revision ID: a4d5e6f7b8c9
Revises: f3c4d5e6a7b8
"""

from alembic import op
import sqlalchemy as sa


revision = "a4d5e6f7b8c9"
down_revision = "f3c4d5e6a7b8"
branch_labels = None
depends_on = None


def upgrade() -> None:
    # T02 made aliases immutable.  Rollback needs exactly one controlled
    # exception: the alias created by this operation may become canonical while
    # that same operation is in rollback-preflight.  Ownership, spelling,
    # protection, and provenance remain immutable.
    op.execute(
        sa.text(
            """
            CREATE OR REPLACE FUNCTION guard_repository_slug_history()
            RETURNS trigger AS $$
            BEGIN
                IF TG_OP = 'DELETE' THEN
                    RAISE EXCEPTION 'repository slug rows are durable';
                END IF;
                IF NEW.repo_id IS DISTINCT FROM OLD.repo_id
                   OR NEW.slug IS DISTINCT FROM OLD.slug THEN
                    RAISE EXCEPTION 'repository slug ownership is immutable';
                END IF;
                IF OLD.kind = 'alias' AND ROW(
                    NEW.kind, NEW.protected, NEW.source_operation_id
                ) IS DISTINCT FROM ROW(
                    OLD.kind, OLD.protected, OLD.source_operation_id
                ) THEN
                    IF NOT (
                        NEW.kind = 'canonical'
                        AND NEW.protected
                        AND NEW.source_operation_id = OLD.source_operation_id
                        AND EXISTS (
                            SELECT 1
                            FROM repository_rename_operations operation
                            WHERE operation.id = OLD.source_operation_id
                              AND operation.repo_id = OLD.repo_id
                              AND operation.phase = 'rollback-preflight'
                        )
                    ) THEN
                        RAISE EXCEPTION 'protected repository alias is immutable';
                    END IF;
                END IF;
                RETURN NEW;
            END;
            $$ LANGUAGE plpgsql
            """
        )
    )


def downgrade() -> None:
    op.execute(
        sa.text(
            """
            CREATE OR REPLACE FUNCTION guard_repository_slug_history()
            RETURNS trigger AS $$
            BEGIN
                IF TG_OP = 'DELETE' THEN
                    RAISE EXCEPTION 'repository slug rows are durable';
                END IF;
                IF NEW.repo_id IS DISTINCT FROM OLD.repo_id
                   OR NEW.slug IS DISTINCT FROM OLD.slug THEN
                    RAISE EXCEPTION 'repository slug ownership is immutable';
                END IF;
                IF OLD.kind = 'alias' AND ROW(
                    NEW.kind, NEW.protected, NEW.source_operation_id
                ) IS DISTINCT FROM ROW(
                    OLD.kind, OLD.protected, OLD.source_operation_id
                ) THEN
                    RAISE EXCEPTION 'protected repository alias is immutable';
                END IF;
                RETURN NEW;
            END;
            $$ LANGUAGE plpgsql
            """
        )
    )
