"""convert_prices_to_integer_cents

Revision ID: e1f2a3b4c5d6
Revises: c00d2985701f
Create Date: 2025-12-20 21:30:00.000000

Converts all price/amount columns from Float to Integer cents.
This follows e-commerce best practices (Stripe, PayPal, Shopify) for
precise monetary calculations.

Example: €105.91 is stored as 10591 (integer cents)

Affected tables:
- products: price, sale_price, supplier_cost, margin_percent
- orders: subtotal, tax_amount, shipping_amount, discount_amount, total_amount
- order_items: unit_price, total_price
- cart_items: price_at_add
- marketplace_products: price_numeric, sale_price_numeric

See docs/architecture/money-handling.md for full documentation.
"""

from collections.abc import Sequence

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "e1f2a3b4c5d6"
down_revision: str | None = "c00d2985701f"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
    # SQLite requires batch mode for column alterations
    # Strategy: Add new _cents columns, migrate data, drop old columns

    # === PRODUCTS TABLE ===
    with op.batch_alter_table("products", schema=None) as batch_op:
        # Add new cents columns
        batch_op.add_column(sa.Column("price_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("sale_price_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("supplier_cost_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("margin_percent_x100", sa.Integer(), nullable=True))

    # Migrate data for products
    op.execute("UPDATE products SET price_cents = ROUND(COALESCE(price, 0) * 100)")
    op.execute("UPDATE products SET sale_price_cents = ROUND(sale_price * 100) WHERE sale_price IS NOT NULL")
    op.execute("UPDATE products SET supplier_cost_cents = ROUND(supplier_cost * 100) WHERE supplier_cost IS NOT NULL")
    op.execute("UPDATE products SET margin_percent_x100 = ROUND(margin_percent * 100) WHERE margin_percent IS NOT NULL")

    # Drop old columns
    with op.batch_alter_table("products", schema=None) as batch_op:
        batch_op.drop_column("price")
        batch_op.drop_column("sale_price")
        batch_op.drop_column("supplier_cost")
        batch_op.drop_column("margin_percent")

    # === ORDERS TABLE ===
    with op.batch_alter_table("orders", schema=None) as batch_op:
        batch_op.add_column(sa.Column("subtotal_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("tax_amount_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("shipping_amount_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("discount_amount_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("total_amount_cents", sa.Integer(), nullable=True))

    # Migrate data for orders
    op.execute("UPDATE orders SET subtotal_cents = ROUND(COALESCE(subtotal, 0) * 100)")
    op.execute("UPDATE orders SET tax_amount_cents = ROUND(COALESCE(tax_amount, 0) * 100)")
    op.execute("UPDATE orders SET shipping_amount_cents = ROUND(COALESCE(shipping_amount, 0) * 100)")
    op.execute("UPDATE orders SET discount_amount_cents = ROUND(COALESCE(discount_amount, 0) * 100)")
    op.execute("UPDATE orders SET total_amount_cents = ROUND(COALESCE(total_amount, 0) * 100)")

    # Make total_amount_cents NOT NULL after migration
    with op.batch_alter_table("orders", schema=None) as batch_op:
        batch_op.drop_column("subtotal")
        batch_op.drop_column("tax_amount")
        batch_op.drop_column("shipping_amount")
        batch_op.drop_column("discount_amount")
        batch_op.drop_column("total_amount")
        # Alter total_amount_cents to be NOT NULL
        batch_op.alter_column("total_amount_cents",
                              existing_type=sa.Integer(),
                              nullable=False)

    # === ORDER_ITEMS TABLE ===
    with op.batch_alter_table("order_items", schema=None) as batch_op:
        batch_op.add_column(sa.Column("unit_price_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("total_price_cents", sa.Integer(), nullable=True))

    # Migrate data for order_items
    op.execute("UPDATE order_items SET unit_price_cents = ROUND(COALESCE(unit_price, 0) * 100)")
    op.execute("UPDATE order_items SET total_price_cents = ROUND(COALESCE(total_price, 0) * 100)")

    with op.batch_alter_table("order_items", schema=None) as batch_op:
        batch_op.drop_column("unit_price")
        batch_op.drop_column("total_price")
        batch_op.alter_column("unit_price_cents",
                              existing_type=sa.Integer(),
                              nullable=False)
        batch_op.alter_column("total_price_cents",
                              existing_type=sa.Integer(),
                              nullable=False)

    # === CART_ITEMS TABLE ===
    with op.batch_alter_table("cart_items", schema=None) as batch_op:
        batch_op.add_column(sa.Column("price_at_add_cents", sa.Integer(), nullable=True))

    # Migrate data for cart_items
    op.execute("UPDATE cart_items SET price_at_add_cents = ROUND(COALESCE(price_at_add, 0) * 100)")

    with op.batch_alter_table("cart_items", schema=None) as batch_op:
        batch_op.drop_column("price_at_add")
        batch_op.alter_column("price_at_add_cents",
                              existing_type=sa.Integer(),
                              nullable=False)

    # === MARKETPLACE_PRODUCTS TABLE ===
    with op.batch_alter_table("marketplace_products", schema=None) as batch_op:
        batch_op.add_column(sa.Column("price_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("sale_price_cents", sa.Integer(), nullable=True))
        batch_op.add_column(sa.Column("weight_grams", sa.Integer(), nullable=True))

    # Migrate data for marketplace_products
    op.execute("UPDATE marketplace_products SET price_cents = ROUND(price_numeric * 100) WHERE price_numeric IS NOT NULL")
    op.execute("UPDATE marketplace_products SET sale_price_cents = ROUND(sale_price_numeric * 100) WHERE sale_price_numeric IS NOT NULL")
    op.execute("UPDATE marketplace_products SET weight_grams = ROUND(weight * 1000) WHERE weight IS NOT NULL")

    with op.batch_alter_table("marketplace_products", schema=None) as batch_op:
        batch_op.drop_column("price_numeric")
        batch_op.drop_column("sale_price_numeric")
        batch_op.drop_column("weight")


def downgrade() -> None:
    # === MARKETPLACE_PRODUCTS TABLE ===
    with op.batch_alter_table("marketplace_products", schema=None) as batch_op:
        batch_op.add_column(sa.Column("price_numeric", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("sale_price_numeric", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("weight", sa.Float(), nullable=True))

    op.execute("UPDATE marketplace_products SET price_numeric = price_cents / 100.0 WHERE price_cents IS NOT NULL")
    op.execute("UPDATE marketplace_products SET sale_price_numeric = sale_price_cents / 100.0 WHERE sale_price_cents IS NOT NULL")
    op.execute("UPDATE marketplace_products SET weight = weight_grams / 1000.0 WHERE weight_grams IS NOT NULL")

    with op.batch_alter_table("marketplace_products", schema=None) as batch_op:
        batch_op.drop_column("price_cents")
        batch_op.drop_column("sale_price_cents")
        batch_op.drop_column("weight_grams")

    # === CART_ITEMS TABLE ===
    with op.batch_alter_table("cart_items", schema=None) as batch_op:
        batch_op.add_column(sa.Column("price_at_add", sa.Float(), nullable=True))

    op.execute("UPDATE cart_items SET price_at_add = price_at_add_cents / 100.0")

    with op.batch_alter_table("cart_items", schema=None) as batch_op:
        batch_op.drop_column("price_at_add_cents")
        batch_op.alter_column("price_at_add",
                              existing_type=sa.Float(),
                              nullable=False)

    # === ORDER_ITEMS TABLE ===
    with op.batch_alter_table("order_items", schema=None) as batch_op:
        batch_op.add_column(sa.Column("unit_price", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("total_price", sa.Float(), nullable=True))

    op.execute("UPDATE order_items SET unit_price = unit_price_cents / 100.0")
    op.execute("UPDATE order_items SET total_price = total_price_cents / 100.0")

    with op.batch_alter_table("order_items", schema=None) as batch_op:
        batch_op.drop_column("unit_price_cents")
        batch_op.drop_column("total_price_cents")
        batch_op.alter_column("unit_price",
                              existing_type=sa.Float(),
                              nullable=False)
        batch_op.alter_column("total_price",
                              existing_type=sa.Float(),
                              nullable=False)

    # === ORDERS TABLE ===
    with op.batch_alter_table("orders", schema=None) as batch_op:
        batch_op.add_column(sa.Column("subtotal", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("tax_amount", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("shipping_amount", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("discount_amount", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("total_amount", sa.Float(), nullable=True))

    op.execute("UPDATE orders SET subtotal = subtotal_cents / 100.0")
    op.execute("UPDATE orders SET tax_amount = tax_amount_cents / 100.0")
    op.execute("UPDATE orders SET shipping_amount = shipping_amount_cents / 100.0")
    op.execute("UPDATE orders SET discount_amount = discount_amount_cents / 100.0")
    op.execute("UPDATE orders SET total_amount = total_amount_cents / 100.0")

    with op.batch_alter_table("orders", schema=None) as batch_op:
        batch_op.drop_column("subtotal_cents")
        batch_op.drop_column("tax_amount_cents")
        batch_op.drop_column("shipping_amount_cents")
        batch_op.drop_column("discount_amount_cents")
        batch_op.drop_column("total_amount_cents")
        batch_op.alter_column("total_amount",
                              existing_type=sa.Float(),
                              nullable=False)

    # === PRODUCTS TABLE ===
    with op.batch_alter_table("products", schema=None) as batch_op:
        batch_op.add_column(sa.Column("price", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("sale_price", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("supplier_cost", sa.Float(), nullable=True))
        batch_op.add_column(sa.Column("margin_percent", sa.Float(), nullable=True))

    op.execute("UPDATE products SET price = price_cents / 100.0 WHERE price_cents IS NOT NULL")
    op.execute("UPDATE products SET sale_price = sale_price_cents / 100.0 WHERE sale_price_cents IS NOT NULL")
    op.execute("UPDATE products SET supplier_cost = supplier_cost_cents / 100.0 WHERE supplier_cost_cents IS NOT NULL")
    op.execute("UPDATE products SET margin_percent = margin_percent_x100 / 100.0 WHERE margin_percent_x100 IS NOT NULL")

    with op.batch_alter_table("products", schema=None) as batch_op:
        batch_op.drop_column("price_cents")
        batch_op.drop_column("sale_price_cents")
        batch_op.drop_column("supplier_cost_cents")
        batch_op.drop_column("margin_percent_x100")
