"""enable_rls_phase1

Revision ID: c5f48b9890f9
Revises: 0b470d9e6cf1
Create Date: 2026-04-10 04:01:13.043321

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


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

_NULL_UUID = "00000000-0000-0000-0000-000000000000"
_PLATFORM_UUID = "00000000-0000-0000-0000-000000000001"
_CURRENT_ACCOUNT = (
    f"COALESCE(NULLIF(current_setting('app.current_account_id', TRUE), ''), "
    f"'{_NULL_UUID}')::uuid"
)


def upgrade() -> None:
    # ── trees ───────────────────────────────────────────────────────────────
    # Extended policy mirrors can_access_tree() in app/core/permissions.py.
    # Tenant sees: own rows, platform rows, any default tree, any public tree,
    # any gallery-featured tree.
    # is_gallery_featured = TRUE is included because /public/templates is a
    # no-auth endpoint — no tenant context is set, so gallery trees must pass
    # RLS on their own flag rather than relying on account_id or is_public.
    # Private/team trees from other accounts are hidden.
    op.execute("ALTER TABLE trees ENABLE ROW LEVEL SECURITY")
    op.execute("ALTER TABLE trees FORCE ROW LEVEL SECURITY")
    op.execute(f"""
        CREATE POLICY tenant_isolation ON trees
            USING (
                account_id = {_CURRENT_ACCOUNT}
                OR account_id = '{_PLATFORM_UUID}'::uuid
                OR is_default = TRUE
                OR is_public = TRUE
                OR is_gallery_featured = TRUE
            )
    """)

    # ── tree_tags ────────────────────────────────────────────────────────────
    # Own account + platform tags (global tags visible to all tenants).
    op.execute("ALTER TABLE tree_tags ENABLE ROW LEVEL SECURITY")
    op.execute("ALTER TABLE tree_tags FORCE ROW LEVEL SECURITY")
    op.execute(f"""
        CREATE POLICY tenant_isolation ON tree_tags
            USING (
                account_id = {_CURRENT_ACCOUNT}
                OR account_id = '{_PLATFORM_UUID}'::uuid
            )
    """)

    # ── tree_categories ──────────────────────────────────────────────────────
    op.execute("ALTER TABLE tree_categories ENABLE ROW LEVEL SECURITY")
    op.execute("ALTER TABLE tree_categories FORCE ROW LEVEL SECURITY")
    op.execute(f"""
        CREATE POLICY tenant_isolation ON tree_categories
            USING (
                account_id = {_CURRENT_ACCOUNT}
                OR account_id = '{_PLATFORM_UUID}'::uuid
            )
    """)

    # ── step_categories ──────────────────────────────────────────────────────
    op.execute("ALTER TABLE step_categories ENABLE ROW LEVEL SECURITY")
    op.execute("ALTER TABLE step_categories FORCE ROW LEVEL SECURITY")
    op.execute(f"""
        CREATE POLICY tenant_isolation ON step_categories
            USING (
                account_id = {_CURRENT_ACCOUNT}
                OR account_id = '{_PLATFORM_UUID}'::uuid
            )
    """)

    # ── psa_connections ──────────────────────────────────────────────────────
    # Tenant-only — PSA credentials must never cross tenant boundaries.
    op.execute("ALTER TABLE psa_connections ENABLE ROW LEVEL SECURITY")
    op.execute("ALTER TABLE psa_connections FORCE ROW LEVEL SECURITY")
    op.execute(f"""
        CREATE POLICY tenant_isolation ON psa_connections
            USING (account_id = {_CURRENT_ACCOUNT})
    """)

    # ── flow_proposals ────────────────────────────────────────────────────────
    # Tenant-only.
    op.execute("ALTER TABLE flow_proposals ENABLE ROW LEVEL SECURITY")
    op.execute("ALTER TABLE flow_proposals FORCE ROW LEVEL SECURITY")
    op.execute(f"""
        CREATE POLICY tenant_isolation ON flow_proposals
            USING (account_id = {_CURRENT_ACCOUNT})
    """)


def downgrade() -> None:
    for table in ["trees", "tree_tags", "tree_categories", "step_categories",
                  "psa_connections", "flow_proposals"]:
        op.execute(f"DROP POLICY IF EXISTS tenant_isolation ON {table}")
        op.execute(f"ALTER TABLE {table} DISABLE ROW LEVEL SECURITY")
        op.execute(f"ALTER TABLE {table} NO FORCE ROW LEVEL SECURITY")
