"""Provider-neutral payment-checkout: Stripe or PayPal adapters.

Checkout `order` stays job-keyed. Provider Orders/Invoices stay provider
objects. Capture and refund are verbs on that checkout order, not
order_record or invoice_record.

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

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

revision = "161"
down_revision = "160"
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)),
)

_ORDER_STATUS = [
    "pending",
    "authorized",
    "paid",
    "failed",
    "canceled",
    "expired",
    "refunded",
    "partially_refunded",
]

_EXTRA_ACTIONS = (
    "payment.capture",
    "payment.refund",
    "paypal.create_order",
    "paypal.capture_order",
    "paypal.refund_capture",
)

_PRICE_FIELDS = [
    {"key": "stripe_price_id", "name": "Stripe Price ID", "type": "text", "indexed": True},
    {"key": "unit_amount", "name": "Unit Amount (minor units)", "type": "number"},
    {"key": "currency", "name": "Currency", "type": "text"},
]

_ORDER_FIELDS = [
    {
        "key": "status",
        "name": "Status",
        "type": "select",
        "indexed": True,
        "options": _ORDER_STATUS,
    },
    {
        "key": "kind",
        "name": "Kind",
        "type": "select",
        "indexed": True,
        "options": ["checkout", "upsell", "additional_purchase", "balance_due"],
    },
    {
        "key": "related_order_id",
        "name": "Related checkout order",
        "type": "relation",
        "relation_entity_key": "order",
        "indexed": True,
    },
    {"key": "provider", "name": "Provider", "type": "text", "indexed": True},
    {
        "key": "provider_checkout_id",
        "name": "Provider checkout ID",
        "type": "text",
        "indexed": True,
    },
    {
        "key": "provider_payment_id",
        "name": "Provider payment ID",
        "type": "text",
        "indexed": True,
    },
    {
        "key": "provider_capture_id",
        "name": "Provider capture ID",
        "type": "text",
        "indexed": True,
    },
    {"key": "amount_paid", "name": "Amount paid", "type": "number"},
    {"key": "amount_refunded", "name": "Amount refunded", "type": "number"},
    {"key": "paid_at", "name": "Paid at", "type": "date"},
]


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)
            if key == "stripe_price_id":
                current.pop("required", None)
            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 == "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.2.0",
    )
    conn.execute(
        sa.update(feature_packs)
        .where(feature_packs.c.slug == "payment-checkout")
        .values(
            composition=stamped,
            version="1.2.0",
            updated_at=datetime.now(UTC),
        )
    )


def downgrade() -> None:
    return
