"""Catalog upsert and authorize-later capture for payment-checkout.

Staff/codegen write Stripe Product/Price (or PayPal unit_amount) through
payment.catalog.upsert. Manual capture is PayPal AUTHORIZE or Stripe
Customer + SetupIntent. Checkout order stays job-keyed.

Revision ID: 162
Revises: 161
"""
from datetime import UTC, datetime

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

revision = "162"
down_revision = "161"
branch_labels = None
depends_on = None

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

_EXTRA_ACTIONS = (
    "payment.catalog.upsert",
    "stripe.create_setup_intent",
    "stripe.update_product",
)

_PRODUCT_FIELDS = [
    {"key": "stripe_product_id", "name": "Stripe Product ID", "type": "text", "indexed": True},
    {"key": "sku", "name": "SKU", "type": "text", "indexed": True},
]

_PRICE_FIELDS = [
    {
        "key": "interval",
        "name": "Interval",
        "type": "select",
        "options": ["one_time", "month", "year"],
    },
]

_ORDER_FIELDS = [
    {
        "key": "capture_mode",
        "name": "Capture mode",
        "type": "select",
        "indexed": True,
        "options": ["immediate", "manual"],
    },
    {
        "key": "provider_customer_id",
        "name": "Provider customer ID",
        "type": "text",
        "indexed": True,
    },
    {
        "key": "provider_payment_method_id",
        "name": "Provider payment method ID",
        "type": "text",
        "indexed": True,
    },
    {
        "key": "provider_setup_id",
        "name": "Provider setup ID",
        "type": "text",
        "indexed": True,
    },
]


def _upsert_fields(entity: dict, fields: list[dict]) -> None:
    schema = entity.setdefault("schema", {})
    if not isinstance(schema, dict):
        return
    existing = schema.setdefault("fields", [])
    if not isinstance(existing, list):
        return
    by_key = {
        str(field.get("key")): index
        for index, field in enumerate(existing)
        if isinstance(field, dict) and field.get("key")
    }
    for field in fields:
        key = str(field["key"])
        if key in by_key:
            current = dict(existing[by_key[key]])
            current.update(field)
            existing[by_key[key]] = current
        else:
            existing.append(dict(field))


def upgrade() -> None:
    from src.domain.feature_packs.normalize import stamp_composition

    conn = op.get_bind()
    row = conn.execute(
        sa.select(feature_packs.c.composition).where(
            feature_packs.c.slug == "payment-checkout"
        )
    ).fetchone()
    if row is None or not isinstance(row[0], dict):
        return
    composition = dict(row[0])
    for entity in composition.get("entities") or []:
        if not isinstance(entity, dict):
            continue
        key = entity.get("entity_key")
        if key == "product":
            _upsert_fields(entity, _PRODUCT_FIELDS)
        elif key == "price":
            _upsert_fields(entity, _PRICE_FIELDS)
        elif key == "order":
            _upsert_fields(entity, _ORDER_FIELDS)
    actions = list(composition.get("connector_actions") or [])
    for action in _EXTRA_ACTIONS:
        if action not in actions:
            actions.append(action)
    composition["connector_actions"] = actions
    stamped = stamp_composition(
        "payment-checkout",
        composition,
        implementation_version="1.3.0",
    )
    conn.execute(
        sa.update(feature_packs)
        .where(feature_packs.c.slug == "payment-checkout")
        .values(
            composition=stamped,
            version="1.3.0",
            updated_at=datetime.now(UTC),
        )
    )


def downgrade() -> None:
    return
