"""create_db_roles

Revision ID: 0b470d9e6cf1
Revises: a9f3b2c1d4e5
Create Date: 2026-04-10 03:58:10.207919

"""
import os
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy import text


# revision identifiers, used by Alembic.
revision: str = '0b470d9e6cf1'
down_revision: Union[str, None] = 'a9f3b2c1d4e5'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # Passwords from env vars. For local dev, defaults are sufficient.
    # For production (Railway), set DB_APP_ROLE_PASSWORD and
    # DB_ADMIN_ROLE_PASSWORD as environment variables before running migrations.
    # Passwords must not contain single quotes.
    app_pw = os.environ.get("DB_APP_ROLE_PASSWORD", "app_secret_change_me")
    admin_pw = os.environ.get("DB_ADMIN_ROLE_PASSWORD", "admin_secret_change_me")

    # Fetch the current database name dynamically — avoids hardcoding
    # (the DB is named 'resolutionflow' in dev, potentially different elsewhere).
    conn = op.get_bind()
    db_name = conn.execute(text("SELECT current_database()")).scalar()

    # ── Application role ────────────────────────────────────────────────────
    # Subject to RLS. Used by FastAPI at runtime via DATABASE_URL.
    op.execute(f"""
        DO $$
        BEGIN
            IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'resolutionflow_app') THEN
                CREATE ROLE resolutionflow_app LOGIN PASSWORD '{app_pw}';
            ELSE
                ALTER ROLE resolutionflow_app LOGIN PASSWORD '{app_pw}';
            END IF;
        END $$
    """)
    op.execute(f"GRANT CONNECT ON DATABASE {db_name} TO resolutionflow_app")
    op.execute("GRANT USAGE ON SCHEMA public TO resolutionflow_app")
    op.execute(
        "GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public "
        "TO resolutionflow_app"
    )
    op.execute(
        "GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO resolutionflow_app"
    )
    # Ensure future tables automatically get the same permissions
    op.execute(
        "ALTER DEFAULT PRIVILEGES IN SCHEMA public "
        "GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO resolutionflow_app"
    )
    op.execute(
        "ALTER DEFAULT PRIVILEGES IN SCHEMA public "
        "GRANT USAGE, SELECT ON SEQUENCES TO resolutionflow_app"
    )

    # ── Admin role ──────────────────────────────────────────────────────────
    # BYPASSRLS. Used by Alembic (DATABASE_URL_SYNC) and /admin/* endpoints
    # (ADMIN_DATABASE_URL) after Task 11.
    op.execute(f"""
        DO $$
        BEGIN
            IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'resolutionflow_admin') THEN
                CREATE ROLE resolutionflow_admin LOGIN PASSWORD '{admin_pw}';
            ELSE
                ALTER ROLE resolutionflow_admin LOGIN PASSWORD '{admin_pw}';
            END IF;
        END $$
    """)
    op.execute("GRANT resolutionflow_app TO resolutionflow_admin")
    op.execute("ALTER ROLE resolutionflow_admin BYPASSRLS")
    op.execute(f"GRANT CONNECT ON DATABASE {db_name} TO resolutionflow_admin")


def downgrade() -> None:
    conn = op.get_bind()
    db_name = conn.execute(text("SELECT current_database()")).scalar()

    op.execute(
        "REVOKE ALL ON ALL TABLES IN SCHEMA public FROM resolutionflow_app"
    )
    op.execute(
        "REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM resolutionflow_app"
    )
    op.execute(
        f"REVOKE CONNECT ON DATABASE {db_name} FROM resolutionflow_app"
    )
    op.execute(
        f"REVOKE CONNECT ON DATABASE {db_name} FROM resolutionflow_admin"
    )
    op.execute("DROP ROLE IF EXISTS resolutionflow_admin")
    op.execute("DROP ROLE IF EXISTS resolutionflow_app")
