"""Add canonical declarative Composition Recipes."""

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

revision = "183"
down_revision = "182"
branch_labels = None
depends_on = None


def upgrade() -> None:
    op.create_table(
        "composition_recipes",
        sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
        sa.Column("slug", sa.String(160), nullable=False),
        sa.Column("name", sa.String(160), nullable=False),
        sa.Column("description", sa.Text(), nullable=False, server_default=""),
        sa.Column("project_types", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("starter_id", sa.String(120), nullable=False),
        sa.Column("required_feature_packs", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("optional_feature_packs", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("required_app_blocks", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("optional_app_blocks", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("required_capabilities", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("optional_capabilities", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("entity_roles", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("presentation", postgresql.JSONB(), nullable=False, server_default="{}"),
        sa.Column("operational", postgresql.JSONB(), nullable=False, server_default="{}"),
        sa.Column("provider_requirements", postgresql.JSONB(), nullable=False, server_default="[]"),
        sa.Column("version", sa.Integer(), nullable=False, server_default="1"),
        sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.true()),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
        sa.UniqueConstraint("slug", name="uq_composition_recipes_slug"),
    )
    op.create_index("ix_composition_recipes_active", "composition_recipes", ["is_active"])
    op.add_column(
        "prompt_suggestions",
        sa.Column("composition_recipe_id", postgresql.UUID(as_uuid=True), nullable=True),
    )
    op.create_foreign_key(
        "fk_prompt_suggestions_composition_recipe",
        "prompt_suggestions",
        "composition_recipes",
        ["composition_recipe_id"],
        ["id"],
        ondelete="SET NULL",
    )
    # This is static seed SQL.  Use the driver's SQL execution path rather
    # than sa.text(): JSON object keys such as `"required":true` are otherwise
    # parsed by SQLAlchemy as bind parameters named `true`.
    op.get_bind().exec_driver_sql("""
      INSERT INTO composition_recipes
        (id, slug, name, description, starter_id, required_feature_packs,
         required_app_blocks, required_capabilities, entity_roles, presentation, operational)
      VALUES
        (gen_random_uuid(), 'shop.ecommerce', 'Ecommerce shop', 'Catalog and order storefront with customer accounts.', 'catalog_orders',
         '["product-catalog", "order-management", "inventory-management"]',
         '["catalog.product", "orders.order", "inventory.stock", "crm.customer"]',
         '["auth", "records"]', '[{"role":"product","required":true},{"role":"order","required":true},{"role":"customer","required":true}]',
         '{"expected_surfaces":["storefront","collection","detail","checkout","account","admin"],"admin_expected":true,"customer_account_expected":true}',
         '{"auth_audiences":["customer","staff"]}'),
        (gen_random_uuid(), 'restaurant.standard', 'Restaurant', 'Public restaurant presence with appointment-based reservations.', 'booking',
         '["appointment-booking", "contact-capture"]',
         '["booking.appointment", "forms.contact", "crm.customer"]',
         '["records"]', '[{"role":"appointment","required":true}]',
         '{"expected_surfaces":["home","menu","reservation","contact"],"admin_expected":true}',
         '{"forms":["reservation","contact"]}'),
        (gen_random_uuid(), 'professional_services.standard', 'Professional services', 'Public services site with inquiry intake and staff follow-up.', 'crm_sales',
         '["contact-capture", "lead-lifecycle"]',
         '["forms.contact", "crm.customer", "crm.lead"]',
         '["records"]', '[{"role":"client","required":true},{"role":"lead","required":true}]',
         '{"expected_surfaces":["home","services","contact","admin"],"admin_expected":true}',
         '{"forms":["contact","consultation"]}'),
        (gen_random_uuid(), 'appointment_service.standard', 'Appointment service', 'Appointment-based service with staff scheduling and customer intake.', 'booking',
         '["appointment-booking", "contact-capture"]',
         '["booking.appointment", "crm.customer", "forms.contact"]',
         '["records"]', '[{"role":"appointment","required":true},{"role":"customer","required":true}]',
         '{"expected_surfaces":["home","services","booking","admin"],"admin_expected":true}',
         '{"forms":["booking"]}'),
        (gen_random_uuid(), 'internal_operations.standard', 'Internal operations', 'Staff-facing operational application with governed records and tasks.', 'internal_operations',
         '["task-management"]',
         '["task.management", "admin.shell", "admin.record_table"]',
         '["auth", "records"]', '[{"role":"work_item","required":true}]',
         '{"expected_surfaces":["admin"],"admin_expected":true,"staff_surface_expected":true}',
         '{"auth_audiences":["staff"]}')
    """)


def downgrade() -> None:
    op.drop_constraint(
        "fk_prompt_suggestions_composition_recipe", "prompt_suggestions", type_="foreignkey"
    )
    op.drop_column("prompt_suggestions", "composition_recipe_id")
    op.drop_index("ix_composition_recipes_active", table_name="composition_recipes")
    op.drop_table("composition_recipes")
