"""Wire RLS + executable functions into the client-portal pack.

v1.0.0 declared client_account/project_update as schema-only entities with
function_slugs: [] and no rls_enabled -- any project's own generated app code
had to invent its own account-scoping logic, and nothing stopped one customer
from reading another's project_update rows. Adds rls_enabled: true to both
entities and wires function_slugs to the two new library functions
(client-portal-create-account, client-portal-post-update, seeded via
scripts/seed_function_library.py before this migration runs), which are the
only supported way to create these records going forward (they compute
owner_user_id correctly; hand-rolled record creates on an rls_enabled entity
require an internal caller to supply owner_user_id explicitly).

Existing installs: PackInstallService.install_pack now reconciles rls_enabled
on an already-existing entity via patch_project_entity when create returns
already_exists, so re-running codegen (or an explicit pack reinstall) turns
RLS on for a project that installed client-portal before this migration. That
does not retroactively fix owner_user_id on records created before RLS
existed -- see scripts/backfill_client_portal_ownership.py, run once per
already-installed project after reinstalling.

Revision ID: 109
Revises: 108
"""
from datetime import datetime, timezone

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

revision = "109"
down_revision = "108"
branch_labels = None
depends_on = None

feature_packs = sa.table(
    "feature_packs",
    sa.column("slug", sa.String),
    sa.column("version", sa.String),
    sa.column("composition", postgresql.JSONB),
    sa.column("input_schema", postgresql.JSONB),
    sa.column("updated_at", sa.DateTime(timezone=True)),
)

_CLIENT_ACCOUNT_ENTITY_V1 = {
    "entity_key": "client_account",
    "name": "Client Account",
    "plural_name": "Client Accounts",
    "schema": {
        "fields": [
            {"key": "app_user_id", "name": "App User", "type": "text", "required": True, "indexed": True},
            {"key": "company_name", "name": "Company Name", "type": "text"},
            {"key": "stripe_customer_id", "name": "Stripe Customer ID", "type": "text", "indexed": True},
        ],
    },
}

_PROJECT_UPDATE_ENTITY_V1 = {
    "entity_key": "project_update",
    "name": "Project Update",
    "plural_name": "Project Updates",
    "schema": {
        "fields": [
            {"key": "client_account_record_id", "name": "Client Account", "type": "relation",
             "relation_entity_key": "client_account", "required": True, "indexed": True},
            {"key": "title", "name": "Title", "type": "text", "required": True},
            {"key": "body", "name": "Body", "type": "text", "required": True},
            {"key": "visibility", "name": "Visibility", "type": "select",
             "options": ["client", "internal"], "indexed": True},
        ],
    },
}

_CLIENT_ACCOUNT_ENTITY_V1_1 = {**_CLIENT_ACCOUNT_ENTITY_V1, "rls_enabled": True}
_PROJECT_UPDATE_ENTITY_V1_1 = {**_PROJECT_UPDATE_ENTITY_V1, "rls_enabled": True}

_COMPOSITION_V1_1 = {
    "entities": [_CLIENT_ACCOUNT_ENTITY_V1_1, _PROJECT_UPDATE_ENTITY_V1_1],
    "requires": [],
    "requires_connections": ["stripe"],
    "connector_actions": [
        "stripe.create_customer",
        "stripe.create_invoice",
        "stripe.create_billing_portal_session",
    ],
    "function_slugs": ["client-portal-create-account", "client-portal-post-update"],
}

_COMPOSITION_V1_0 = {
    "entities": [_CLIENT_ACCOUNT_ENTITY_V1, _PROJECT_UPDATE_ENTITY_V1],
    "requires": ["stripe"],
    "connector_actions": [
        "stripe.create_customer",
        "stripe.create_invoice",
        "stripe.create_billing_portal_session",
    ],
    "function_slugs": [],
}

_INPUT_SCHEMA = {
    "type": "object",
    "properties": {
        "crm_sync_connector_action": {
            "type": "string",
            "description": "Optional connector action to mirror client accounts externally, e.g. salesforce.upsert_contact.",
        },
    },
}


def upgrade() -> None:
    op.execute(
        sa.update(feature_packs)
        .where(feature_packs.c.slug == "client-portal")
        .values(
            version="1.1.0",
            composition=_COMPOSITION_V1_1,
            input_schema=_INPUT_SCHEMA,
            updated_at=datetime.now(timezone.utc),
        )
    )


def downgrade() -> None:
    op.execute(
        sa.update(feature_packs)
        .where(feature_packs.c.slug == "client-portal")
        .values(
            version="1.0.0",
            composition=_COMPOSITION_V1_0,
            input_schema=_INPUT_SCHEMA,
            updated_at=datetime.now(timezone.utc),
        )
    )
