"""Order management service."""

import logging
from datetime import datetime
from uuid import UUID

from sqlalchemy import select, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.config import get_settings
from app.models.order import Order, OrderItem, OrderStatus
from app.models.customer import Customer
from app.models.cart import Cart
from app.schemas.order import OrderResponse, OrderItemResponse
from app.services.flow_service import FlowService
from app.pod.printful_client import PrintfulClient
from app.pod.prodigi_client import ProdigiClient
from app.services.design_service import DesignService
from app.services.email_service import EmailService

logger = logging.getLogger(__name__)
settings = get_settings()


class OrderService:
    """Service for order operations."""

    def __init__(self, db: AsyncSession):
        self.db = db

    async def get_order_by_id(self, order_id: UUID) -> OrderResponse | None:
        """Get order by ID."""
        result = await self.db.execute(
            select(Order)
            .where(Order.id == order_id)
            .options(selectinload(Order.items))
        )
        order = result.scalar_one_or_none()
        if not order:
            return None
        return self._order_to_response(order)

    async def get_order_by_id_and_email(
        self,
        order_id: UUID,
        email: str,
    ) -> OrderResponse | None:
        """Get order by ID with email verification."""
        result = await self.db.execute(
            select(Order)
            .where(Order.id == order_id, Order.shipping_email == email)
            .options(selectinload(Order.items))
        )
        order = result.scalar_one_or_none()
        if not order:
            return None
        return self._order_to_response(order)

    async def list_orders(
        self,
        status: OrderStatus | None = None,
        limit: int = 50,
        offset: int = 0,
    ) -> list[OrderResponse]:
        """List orders with optional status filter."""
        query = select(Order).options(selectinload(Order.items))
        if status:
            query = query.where(Order.status == status.value)
        query = query.order_by(Order.created_at.desc()).limit(limit).offset(offset)

        result = await self.db.execute(query)
        orders = result.scalars().all()
        return [self._order_to_response(o) for o in orders]

    async def update_status(
        self,
        order_id: UUID,
        status: OrderStatus,
    ) -> OrderResponse | None:
        """Update order status."""
        result = await self.db.execute(
            select(Order)
            .where(Order.id == order_id)
            .options(selectinload(Order.items))
        )
        order = result.scalar_one_or_none()
        if not order:
            return None

        order.status = status.value
        if status == OrderStatus.SHIPPED:
            order.shipped_at = datetime.utcnow()
        elif status == OrderStatus.DELIVERED:
            order.delivered_at = datetime.utcnow()

        await self.db.commit()
        return self._order_to_response(order)

    async def handle_successful_payment(self, payment: dict):
        """Handle successful Mollie payment.

        Called by the Mollie webhook when payment status is 'paid'.
        Mollie payment object contains metadata with cart_id.
        """
        cart_id = payment.get("metadata", {}).get("cart_id")
        if not cart_id:
            return

        # Get cart
        result = await self.db.execute(
            select(Cart)
            .where(Cart.id == UUID(cart_id))
            .options(selectinload(Cart.items))
        )
        cart = result.scalar_one_or_none()
        if not cart or not cart.items:
            return

        # Extract amount from Mollie payment
        amount = payment.get("amount", {})
        total = float(amount.get("value", "0"))
        currency = amount.get("currency", "USD")

        # Create order
        order = Order(
            payment_provider="mollie",
            payment_id=payment.get("id"),
            payment_method=payment.get("method"),
            status=OrderStatus.PAID.value,
            shipping_email=payment.get("metadata", {}).get("email", ""),
            subtotal=total,
            total=total,
            currency=currency,
            paid_at=datetime.utcnow(),
        )
        self.db.add(order)
        await self.db.flush()

        # Create order items
        for cart_item in cart.items:
            order_item = OrderItem(
                order_id=order.id,
                product_slug=cart_item.product_slug,
                product_name=cart_item.product_name,
                variant=cart_item.variant,
                quantity=cart_item.quantity,
                unit_price=float(cart_item.unit_price),
                pod_status="pending",
            )
            self.db.add(order_item)

        await self.db.commit()

        # Route revenue margin to TBFF flow → bonding curve
        await self._deposit_revenue_to_flow(order)

        # Submit to POD providers
        await self._submit_to_pod(order)

        # Send confirmation email (non-blocking — don't fail the order if email fails)
        try:
            email_service = EmailService()
            await email_service.send_order_confirmation(
                to_email=order.shipping_email or "",
                to_name=order.shipping_name,
                order_id=str(order.id),
                items=[
                    {
                        "product_name": item.product_name,
                        "variant": item.variant,
                        "quantity": item.quantity,
                        "unit_price": float(item.unit_price),
                    }
                    for item in order.items
                ],
                total=float(order.total),
                currency=order.currency or "USD",
            )
        except Exception as e:
            logger.error(f"Failed to send confirmation email for order {order.id}: {e}")

    async def update_pod_status(
        self,
        pod_provider: str,
        pod_order_id: str,
        status: str,
        tracking_number: str | None = None,
        tracking_url: str | None = None,
    ):
        """Update POD status for order items."""
        await self.db.execute(
            update(OrderItem)
            .where(
                OrderItem.pod_provider == pod_provider,
                OrderItem.pod_order_id == pod_order_id,
            )
            .values(
                pod_status=status,
                pod_tracking_number=tracking_number,
                pod_tracking_url=tracking_url,
            )
        )
        await self.db.commit()

        # Send shipping notification when items ship
        if status in ("shipped", "in_transit") and tracking_number:
            await self._send_shipping_email(
                pod_provider=pod_provider,
                pod_order_id=pod_order_id,
                tracking_number=tracking_number,
                tracking_url=tracking_url,
            )

    async def _send_shipping_email(
        self,
        pod_provider: str,
        pod_order_id: str,
        tracking_number: str | None,
        tracking_url: str | None,
    ):
        """Send shipping notification for an order."""
        try:
            # Find the order via its items
            result = await self.db.execute(
                select(OrderItem)
                .where(
                    OrderItem.pod_provider == pod_provider,
                    OrderItem.pod_order_id == pod_order_id,
                )
                .limit(1)
            )
            item = result.scalar_one_or_none()
            if not item:
                return

            result = await self.db.execute(
                select(Order).where(Order.id == item.order_id)
            )
            order = result.scalar_one_or_none()
            if not order or not order.shipping_email:
                return

            email_service = EmailService()
            await email_service.send_shipping_notification(
                to_email=order.shipping_email,
                to_name=order.shipping_name,
                order_id=str(order.id),
                tracking_number=tracking_number,
                tracking_url=tracking_url,
            )
        except Exception as e:
            logger.error(f"Failed to send shipping email: {e}")

    async def _submit_to_pod(self, order: Order):
        """Route order items to the correct POD provider for fulfillment.

        Reads each item's design metadata to determine provider (printful/prodigi),
        groups items, and submits separate orders per provider.
        """
        if not order.shipping_address_line1:
            logger.info(f"Order {order.id} has no shipping address, skipping POD")
            return

        design_service = DesignService()
        printful_items = []
        prodigi_items = []

        for item in order.items:
            image_url = f"https://fungiswag.jeffemmett.com/api/designs/{item.product_slug}/image"

            design = await design_service.get_design(item.product_slug)
            provider = "prodigi"  # default
            product_sku = item.variant or item.product_slug

            if design and design.products:
                product_config = design.products[0]
                provider = product_config.provider
                product_sku = product_config.sku

            if provider == "printful":
                # Extract size from variant string (e.g. "71-M" → "M", or just "M")
                size = item.variant or "M"
                if "-" in size:
                    size = size.split("-", 1)[1]

                printful_items.append({
                    "order_item": item,
                    "product_id": int(product_sku),
                    "size": size,
                    "quantity": item.quantity,
                    "image_url": image_url,
                })
            else:
                prodigi_items.append({
                    "order_item": item,
                    "sku": item.variant or item.product_slug,
                    "quantity": item.quantity,
                    "image_url": image_url,
                })

        if printful_items:
            await self._submit_to_printful(order, printful_items)
        if prodigi_items:
            await self._submit_to_prodigi(order, prodigi_items)

    async def _submit_to_printful(self, order: Order, items: list[dict]):
        """Submit items to Printful for fulfillment."""
        printful = PrintfulClient()
        if not printful.enabled:
            logger.info("Printful not configured, skipping")
            return

        order_items = []
        for item_data in items:
            variant_id = await printful.resolve_variant_id(
                product_id=item_data["product_id"],
                size=item_data["size"],
            )
            if not variant_id:
                logger.error(
                    f"Could not resolve Printful variant for product "
                    f"{item_data['product_id']} size {item_data['size']}"
                )
                continue

            order_items.append({
                "catalog_variant_id": variant_id,
                "quantity": item_data["quantity"],
                "image_url": item_data["image_url"],
                "placement": "front_large",
            })

        if not order_items:
            return

        recipient = {
            "name": order.shipping_name or "",
            "address1": order.shipping_address_line1 or "",
            "address2": order.shipping_address_line2 or "",
            "city": order.shipping_city or "",
            "state_code": order.shipping_state or "",
            "country_code": order.shipping_country or "",
            "zip": order.shipping_postal_code or "",
            "email": order.shipping_email or "",
        }

        try:
            result = await printful.create_order(
                items=order_items,
                recipient=recipient,
            )
            pod_order_id = str(result.get("id", ""))

            for item_data in items:
                item_data["order_item"].pod_provider = "printful"
                item_data["order_item"].pod_order_id = pod_order_id
                item_data["order_item"].pod_status = "submitted"

            order.status = OrderStatus.PROCESSING.value
            await self.db.commit()
            logger.info(f"Submitted order {order.id} to Printful: {pod_order_id}")

        except Exception as e:
            logger.error(f"Failed to submit order {order.id} to Printful: {e}")

    async def _submit_to_prodigi(self, order: Order, items: list[dict]):
        """Submit items to Prodigi for fulfillment."""
        prodigi = ProdigiClient()
        if not prodigi.enabled:
            logger.info("Prodigi not configured, skipping")
            return

        prodigi_items = []
        for item_data in items:
            prodigi_items.append({
                "sku": item_data["sku"],
                "copies": item_data["quantity"],
                "sizing": "fillPrintArea",
                "assets": [{"printArea": "default", "url": item_data["image_url"]}],
            })

        recipient = {
            "name": order.shipping_name or "",
            "email": order.shipping_email or "",
            "address": {
                "line1": order.shipping_address_line1 or "",
                "line2": order.shipping_address_line2 or "",
                "townOrCity": order.shipping_city or "",
                "stateOrCounty": order.shipping_state or "",
                "postalOrZipCode": order.shipping_postal_code or "",
                "countryCode": order.shipping_country or "",
            },
        }

        try:
            result = await prodigi.create_order(
                items=prodigi_items,
                recipient=recipient,
                metadata={"rswag_order_id": str(order.id)},
            )
            pod_order_id = result.get("id")

            for item_data in items:
                item_data["order_item"].pod_provider = "prodigi"
                item_data["order_item"].pod_order_id = pod_order_id
                item_data["order_item"].pod_status = "submitted"

            order.status = OrderStatus.PROCESSING.value
            await self.db.commit()
            logger.info(f"Submitted order {order.id} to Prodigi: {pod_order_id}")

        except Exception as e:
            logger.error(f"Failed to submit order {order.id} to Prodigi: {e}")

    async def _deposit_revenue_to_flow(self, order: Order):
        """Calculate margin and deposit to TBFF flow for bonding curve funding.

        Revenue split:
          total sale - POD cost estimate = margin
          margin × flow_revenue_split = amount deposited to flow
          flow → Transak on-ramp → USDC → bonding curve → $MYCO
        """
        split = settings.flow_revenue_split
        if split <= 0:
            return

        total = float(order.total) if order.total else 0
        if total <= 0:
            return

        # Revenue split: configurable fraction of total goes to flow
        # (POD costs + operational expenses kept as fiat remainder)
        flow_amount = round(total * split, 2)

        flow_service = FlowService()
        await flow_service.deposit_revenue(
            amount=flow_amount,
            currency=order.currency or "USD",
            order_id=str(order.id),
            description=f"rSwag sale revenue split ({split:.0%} of ${total:.2f})",
        )

    async def _get_or_create_customer(self, email: str) -> Customer | None:
        """Get or create customer by email."""
        if not email:
            return None

        result = await self.db.execute(
            select(Customer).where(Customer.email == email)
        )
        customer = result.scalar_one_or_none()
        if customer:
            return customer

        customer = Customer(email=email)
        self.db.add(customer)
        await self.db.flush()
        return customer

    def _order_to_response(self, order: Order) -> OrderResponse:
        """Convert Order model to response schema."""
        items = [
            OrderItemResponse(
                id=item.id,
                product_slug=item.product_slug,
                product_name=item.product_name,
                variant=item.variant,
                quantity=item.quantity,
                unit_price=float(item.unit_price),
                pod_provider=item.pod_provider,
                pod_status=item.pod_status,
                pod_tracking_number=item.pod_tracking_number,
                pod_tracking_url=item.pod_tracking_url,
            )
            for item in order.items
        ]

        return OrderResponse(
            id=order.id,
            status=order.status,
            shipping_name=order.shipping_name,
            shipping_email=order.shipping_email,
            shipping_city=order.shipping_city,
            shipping_country=order.shipping_country,
            subtotal=float(order.subtotal) if order.subtotal else None,
            shipping_cost=float(order.shipping_cost) if order.shipping_cost else None,
            tax=float(order.tax) if order.tax else None,
            total=float(order.total) if order.total else None,
            currency=order.currency,
            items=items,
            created_at=order.created_at,
            paid_at=order.paid_at,
            shipped_at=order.shipped_at,
        )
