"""bind_profiles_to_auth_users

Revision ID: 20260224_bind_profiles_auth
Revises: 85d25a191d06
Create Date: 2026-02-24 17:55:00.000000

"""

from typing import Sequence, Union

from alembic import op


# revision identifiers, used by Alembic.
revision: str = "20260224_bind_profiles_auth"
down_revision: Union[str, Sequence[str], None] = "85d25a191d06"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # Remove orphan profiles that are not backed by auth.users.
    # This guarantees FK creation will not fail on historical inconsistent data.
    op.execute(
        """
        DELETE FROM public.profiles p
        WHERE NOT EXISTS (
            SELECT 1
            FROM auth.users u
            WHERE u.id = p.id
        )
        """
    )

    # Backfill profile rows for existing auth users.
    op.execute(
        """
        INSERT INTO public.profiles (id, username, display_name)
        SELECT
            u.id,
            'user_' || substr(replace(u.id::text, '-', ''), 1, 25),
            COALESCE(
                NULLIF(u.raw_user_meta_data->>'display_name', ''),
                NULLIF(u.raw_user_meta_data->>'full_name', '')
            )
        FROM auth.users u
        LEFT JOIN public.profiles p ON p.id = u.id
        WHERE p.id IS NULL
        """
    )

    # Enforce one-to-one binding between profiles.id and auth.users.id.
    op.execute(
        """
        ALTER TABLE public.profiles
        ADD CONSTRAINT fk_profiles_id_auth_users
        FOREIGN KEY (id) REFERENCES auth.users(id)
        ON DELETE CASCADE
        """
    )

    # Auto-create profile rows when new auth users are registered.
    op.execute(
        """
        CREATE OR REPLACE FUNCTION public.create_profile_for_new_user()
        RETURNS trigger
        LANGUAGE plpgsql
        SECURITY DEFINER
        SET search_path = public
        AS $$
        BEGIN
            INSERT INTO public.profiles (id, username, display_name)
            VALUES (
                NEW.id,
                'user_' || substr(replace(NEW.id::text, '-', ''), 1, 25),
                COALESCE(
                    NULLIF(NEW.raw_user_meta_data->>'display_name', ''),
                    NULLIF(NEW.raw_user_meta_data->>'full_name', '')
                )
            )
            ON CONFLICT (id) DO NOTHING;

            RETURN NEW;
        END;
        $$
        """
    )

    op.execute(
        """
        DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users
        """
    )
    op.execute(
        """
        CREATE TRIGGER on_auth_user_created
        AFTER INSERT ON auth.users
        FOR EACH ROW
        EXECUTE FUNCTION public.create_profile_for_new_user()
        """
    )


def downgrade() -> None:
    op.execute("DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users")
    op.execute("DROP FUNCTION IF EXISTS public.create_profile_for_new_user()")
    op.execute(
        """
        ALTER TABLE public.profiles
        DROP CONSTRAINT IF EXISTS fk_profiles_id_auth_users
        """
    )
