# app/modules/orders/services/order_service.py
"""
Unified order service for all sales channels.

This service handles:
- Order creation (direct and marketplace)
- Order status management
- Order retrieval and filtering
- Customer creation for marketplace imports
- Order item management

All orders use snapshotted customer and address data.

All monetary calculations use integer cents internally for precision.
See docs/architecture/money-handling.md for details.
"""

import logging
import random
import string
from datetime import UTC, datetime
from typing import Any

from sqlalchemy import and_, func, or_
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session

from app.modules.billing.exceptions import TierLimitExceededException
from app.modules.billing.services.subscription_service import subscription_service
from app.modules.customers.exceptions import CustomerNotFoundException
from app.modules.inventory.exceptions import InsufficientInventoryException
from app.modules.orders.exceptions import (
    OrderNotFoundException,
    OrderValidationException,
)
from app.modules.orders.models.order import Order, OrderItem
from app.modules.orders.schemas.order import (
    OrderCreate,
    OrderUpdate,
)
from app.utils.money import Money, cents_to_euros, euros_to_cents
from app.utils.vat import (
    VATResult,
    calculate_vat_amount,
    determine_vat_regime,
)

# Placeholder product constants
PLACEHOLDER_GTIN = "0000000000000"
PLACEHOLDER_MARKETPLACE_ID = "PLACEHOLDER"

logger = logging.getLogger(__name__)


class OrderService:
    """Unified service for order operations across all channels."""

    # =========================================================================
    # Order Number Generation
    # =========================================================================

    def _generate_order_number(self, db: Session, store_id: int) -> str:
        """
        Generate unique order number.

        Format: ORD-{STORE_ID}-{TIMESTAMP}-{RANDOM}
        Example: ORD-1-20250110-A1B2C3
        """
        timestamp = datetime.now(UTC).strftime("%Y%m%d")
        random_suffix = "".join(
            random.choices(string.ascii_uppercase + string.digits, k=6)
        )
        order_number = f"ORD-{store_id}-{timestamp}-{random_suffix}"

        # Ensure uniqueness
        while db.query(Order).filter(Order.order_number == order_number).first():
            random_suffix = "".join(
                random.choices(string.ascii_uppercase + string.digits, k=6)
            )
            order_number = f"ORD-{store_id}-{timestamp}-{random_suffix}"

        return order_number

    # =========================================================================
    # Tax Calculation
    # =========================================================================

    def _calculate_tax_for_order(
        self,
        db: Session,
        store_id: int,
        subtotal_cents: int,
        billing_country_iso: str,
        buyer_vat_number: str | None = None,
    ) -> VATResult:
        """
        Calculate tax amount for an order based on billing destination.

        Uses the shared VAT utility to determine the correct VAT regime
        and rate, consistent with invoice VAT calculation.
        """
        from app.modules.orders.models.invoice import StoreInvoiceSettings

        # Get store invoice settings for seller country and OSS status
        settings = (
            db.query(StoreInvoiceSettings)
            .filter(StoreInvoiceSettings.store_id == store_id)
            .first()
        )

        # Default to Luxembourg if no settings exist
        seller_country = settings.merchant_country if settings else "LU"
        seller_oss_registered = settings.is_oss_registered if settings else False

        # Determine VAT regime using shared utility
        return determine_vat_regime(
            seller_country=seller_country,
            buyer_country=billing_country_iso or "LU",
            buyer_vat_number=buyer_vat_number,
            seller_oss_registered=seller_oss_registered,
        )

    # =========================================================================
    # Placeholder Product Management
    # =========================================================================

    def _get_or_create_placeholder_product(
        self,
        db: Session,
        store_id: int,
    ):
        """
        Get or create the store's placeholder product for unmatched items.
        """
        from app.modules.catalog.models import Product
        from app.modules.marketplace.models import (  # IMPORT-002
            MarketplaceProduct,
            MarketplaceProductTranslation,
        )

        # Check for existing placeholder product for this store
        placeholder = (
            db.query(Product)
            .filter(
                and_(
                    Product.store_id == store_id,
                    Product.gtin == PLACEHOLDER_GTIN,
                )
            )
            .first()
        )

        if placeholder:
            return placeholder

        # Get or create placeholder marketplace product (shared)
        mp = (
            db.query(MarketplaceProduct)
            .filter(
                MarketplaceProduct.marketplace_product_id == PLACEHOLDER_MARKETPLACE_ID
            )
            .first()
        )

        if not mp:
            mp = MarketplaceProduct(
                marketplace_product_id=PLACEHOLDER_MARKETPLACE_ID,
                marketplace="internal",
                store_name="system",
                product_type_enum="physical",
                is_active=False,
            )
            db.add(mp)
            db.flush()

            # Add translation for placeholder
            translation = MarketplaceProductTranslation(
                marketplace_product_id=mp.id,
                language="en",
                title="Unmatched Product (Pending Resolution)",
                description=(
                    "This is a placeholder for products not found during order import. "
                    "Please resolve the exception to assign the correct product."
                ),
            )
            db.add(translation)
            db.flush()

            logger.info(f"Created placeholder MarketplaceProduct {mp.id}")

        # Create store-specific placeholder product
        placeholder = Product(
            store_id=store_id,
            marketplace_product_id=mp.id,
            gtin=PLACEHOLDER_GTIN,
            gtin_type="placeholder",
            is_active=False,
        )
        db.add(placeholder)
        db.flush()

        logger.info(f"Created placeholder product {placeholder.id} for store {store_id}")

        return placeholder

    # =========================================================================
    # Customer Management
    # =========================================================================

    def find_or_create_customer(
        self,
        db: Session,
        store_id: int,
        email: str,
        first_name: str,
        last_name: str,
        phone: str | None = None,
        is_active: bool = False,
    ):
        """
        Find existing customer by email or create new one.
        """
        from app.modules.customers.services.customer_service import customer_service

        # Look for existing customer by email within store scope
        customer = customer_service.get_customer_by_email(db, store_id, email)
        if customer:
            return customer

        # Create new customer via customer service
        customer = customer_service.create_customer_for_enrollment(
            db, store_id, email,
            first_name=first_name,
            last_name=last_name,
            phone=phone,
        )

        logger.info(
            f"Created customer {customer.id} for store {store_id}: {email}"
        )

        return customer

    # =========================================================================
    # Order Creation
    # =========================================================================

    def create_order(
        self,
        db: Session,
        store_id: int,
        order_data: OrderCreate,
    ) -> Order:
        """
        Create a new direct order.
        """
        # Check tier limit before creating order
        subscription_service.check_order_limit(db, store_id)

        try:
            from app.modules.catalog.models import Product
            from app.modules.customers.services.customer_service import customer_service

            # Get or create customer
            if order_data.customer_id:
                customer = customer_service.get_customer(db, store_id, order_data.customer_id)
            else:
                # Create customer from snapshot
                customer = self.find_or_create_customer(
                    db=db,
                    store_id=store_id,
                    email=order_data.customer.email,
                    first_name=order_data.customer.first_name,
                    last_name=order_data.customer.last_name,
                    phone=order_data.customer.phone,
                    is_active=True,
                )

            # Calculate order totals and validate products
            subtotal_cents = 0
            order_items_data = []

            for item_data in order_data.items:
                product = (
                    db.query(Product)
                    .filter(
                        and_(
                            Product.id == item_data.product_id,
                            Product.store_id == store_id,
                            Product.is_active == True,
                        )
                    )
                    .first()
                )

                if not product:
                    raise OrderValidationException(
                        f"Product {item_data.product_id} not found"
                    )

                # Check inventory
                if product.available_inventory < item_data.quantity:
                    raise InsufficientInventoryException(
                        gtin=getattr(product, "gtin", str(product.id)),
                        location="default",
                        requested=item_data.quantity,
                        available=product.available_inventory,
                    )

                # Get price in cents
                unit_price_cents = (
                    product.sale_price_cents
                    or product.price_cents
                )
                if not unit_price_cents:
                    raise OrderValidationException(f"Product {product.id} has no price")

                # Calculate line total in cents
                line_total_cents = Money.calculate_line_total(
                    unit_price_cents, item_data.quantity
                )
                subtotal_cents += line_total_cents

                order_items_data.append(
                    {
                        "product_id": product.id,
                        "product_name": product.marketplace_product.get_title("en")
                        if product.marketplace_product
                        else str(product.id),
                        "product_sku": product.store_sku,
                        "gtin": product.gtin,
                        "gtin_type": product.gtin_type,
                        "quantity": item_data.quantity,
                        "unit_price_cents": unit_price_cents,
                        "total_price_cents": line_total_cents,
                    }
                )

            # Use billing address or shipping address for VAT
            billing = order_data.billing_address or order_data.shipping_address

            # Calculate VAT using store settings
            vat_result = self._calculate_tax_for_order(
                db=db,
                store_id=store_id,
                subtotal_cents=subtotal_cents,
                billing_country_iso=billing.country_iso,
                buyer_vat_number=getattr(billing, "vat_number", None),
            )

            # Calculate amounts in cents
            tax_amount_cents = calculate_vat_amount(subtotal_cents, vat_result.rate)
            shipping_amount_cents = 599 if subtotal_cents < 5000 else 0
            discount_amount_cents = 0
            total_amount_cents = Money.calculate_order_total(
                subtotal_cents, tax_amount_cents, shipping_amount_cents, discount_amount_cents
            )

            # Generate order number
            order_number = self._generate_order_number(db, store_id)

            # Create order with snapshots
            order = Order(
                store_id=store_id,
                customer_id=customer.id,
                order_number=order_number,
                channel="direct",
                status="pending",
                # Financials
                subtotal_cents=subtotal_cents,
                tax_amount_cents=tax_amount_cents,
                shipping_amount_cents=shipping_amount_cents,
                discount_amount_cents=discount_amount_cents,
                total_amount_cents=total_amount_cents,
                currency="EUR",
                # VAT information
                vat_regime=vat_result.regime.value,
                vat_rate=vat_result.rate,
                vat_rate_label=vat_result.label,
                vat_destination_country=vat_result.destination_country,
                # Customer snapshot
                customer_first_name=order_data.customer.first_name,
                customer_last_name=order_data.customer.last_name,
                customer_email=order_data.customer.email,
                customer_phone=order_data.customer.phone,
                customer_locale=order_data.customer.locale,
                # Shipping address snapshot
                ship_first_name=order_data.shipping_address.first_name,
                ship_last_name=order_data.shipping_address.last_name,
                ship_company=order_data.shipping_address.company,
                ship_address_line_1=order_data.shipping_address.address_line_1,
                ship_address_line_2=order_data.shipping_address.address_line_2,
                ship_city=order_data.shipping_address.city,
                ship_postal_code=order_data.shipping_address.postal_code,
                ship_country_iso=order_data.shipping_address.country_iso,
                # Billing address snapshot
                bill_first_name=billing.first_name,
                bill_last_name=billing.last_name,
                bill_company=billing.company,
                bill_address_line_1=billing.address_line_1,
                bill_address_line_2=billing.address_line_2,
                bill_city=billing.city,
                bill_postal_code=billing.postal_code,
                bill_country_iso=billing.country_iso,
                # Other
                shipping_method=order_data.shipping_method,
                customer_notes=order_data.customer_notes,
                order_date=datetime.now(UTC),
            )

            db.add(order)
            db.flush()

            # Create order items
            order_items = [
                OrderItem(order_id=order.id, **item_data)
                for item_data in order_items_data
            ]
            db.add_all(order_items)

            db.flush()
            db.refresh(order)

            # Increment order count for subscription tracking
            subscription_service.increment_order_count(db, store_id)

            logger.info(
                f"Order {order.order_number} created for store {store_id}, "
                f"total: EUR {cents_to_euros(total_amount_cents):.2f}"
            )

            return order

        except (
            OrderValidationException,
            InsufficientInventoryException,
            CustomerNotFoundException,
            TierLimitExceededException,
        ):
            raise
        except SQLAlchemyError as e:
            logger.error(f"Error creating order: {str(e)}")
            raise OrderValidationException(f"Failed to create order: {str(e)}")

    def create_letzshop_order(
        self,
        db: Session,
        store_id: int,
        shipment_data: dict[str, Any],
        skip_limit_check: bool = False,
    ) -> Order:
        """
        Create an order from Letzshop shipment data.
        """
        from app.modules.catalog.models import Product
        from app.modules.orders.services.order_item_exception_service import (
            order_item_exception_service,
        )

        # Check tier limit before creating order
        if not skip_limit_check:
            can_create, message = subscription_service.can_create_order(db, store_id)
            if not can_create:
                raise TierLimitExceededException(
                    message=message or "Order limit exceeded",
                    limit_type="orders",
                    current=0,
                    limit=0,
                )

        order_data = shipment_data.get("order", {})

        # Generate order number using Letzshop order number
        letzshop_order_number = order_data.get("number", "")
        order_number = f"LS-{store_id}-{letzshop_order_number}"

        # Check if order already exists
        existing = (
            db.query(Order)
            .filter(Order.order_number == order_number)
            .first()
        )
        if existing:
            updated = False

            # Update tracking if available and not already set
            tracking_data = shipment_data.get("tracking") or {}
            new_tracking = tracking_data.get("code") or tracking_data.get("number")
            if new_tracking and not existing.tracking_number:
                existing.tracking_number = new_tracking
                tracking_provider = tracking_data.get("provider")
                if not tracking_provider and tracking_data.get("carrier"):
                    carrier = tracking_data.get("carrier", {})
                    tracking_provider = carrier.get("code") or carrier.get("name")
                existing.tracking_provider = tracking_provider
                updated = True
                logger.info(
                    f"Updated tracking for order {order_number}: "
                    f"{tracking_provider} {new_tracking}"
                )

            # Update shipment number if not already set
            shipment_number = shipment_data.get("number")
            if shipment_number and not existing.shipment_number:
                existing.shipment_number = shipment_number
                updated = True

            # Update carrier if not already set
            shipment_data_obj = shipment_data.get("data") or {}
            if shipment_data_obj and not existing.shipping_carrier:
                carrier_name = shipment_data_obj.get("__typename", "").lower()
                if carrier_name:
                    existing.shipping_carrier = carrier_name
                    updated = True

            if updated:
                existing.updated_at = datetime.now(UTC)

            return existing

        # Parse inventory units
        inventory_units = shipment_data.get("inventoryUnits", [])
        if isinstance(inventory_units, dict):
            inventory_units = inventory_units.get("nodes", [])

        # Collect all GTINs and check for items without GTINs
        gtins = set()
        has_items_without_gtin = False
        for unit in inventory_units:
            variant = unit.get("variant", {}) or {}
            trade_id = variant.get("tradeId", {}) or {}
            gtin = trade_id.get("number")
            if gtin:
                gtins.add(gtin)
            else:
                has_items_without_gtin = True

        # Batch query all products by GTIN
        products_by_gtin: dict[str, Product] = {}
        if gtins:
            products = (
                db.query(Product)
                .filter(
                    and_(
                        Product.store_id == store_id,
                        Product.gtin.in_(gtins),
                    )
                )
                .all()
            )
            products_by_gtin = {p.gtin: p for p in products if p.gtin}

        # Identify missing GTINs
        missing_gtins = gtins - set(products_by_gtin.keys())
        placeholder = None
        if missing_gtins or has_items_without_gtin:
            placeholder = self._get_or_create_placeholder_product(db, store_id)
            if missing_gtins:
                logger.warning(
                    f"Order {order_number}: {len(missing_gtins)} product(s) not found. "
                    f"GTINs: {missing_gtins}. Using placeholder and creating exceptions."
                )
            if has_items_without_gtin:
                logger.warning(
                    f"Order {order_number}: Some items have no GTIN. "
                    f"Using placeholder and creating exceptions."
                )

        # Parse address data
        ship_address = order_data.get("shipAddress", {}) or {}
        bill_address = order_data.get("billAddress", {}) or {}
        ship_country = ship_address.get("country", {}) or {}
        bill_country = bill_address.get("country", {}) or {}

        # Extract customer info
        customer_email = order_data.get("email", "")
        ship_first_name = ship_address.get("firstName", "") or ""
        ship_last_name = ship_address.get("lastName", "") or ""

        # Parse order date
        order_date = datetime.now(UTC)
        completed_at_str = order_data.get("completedAt")
        if completed_at_str:
            try:
                if completed_at_str.endswith("Z"):
                    completed_at_str = completed_at_str[:-1] + "+00:00"
                order_date = datetime.fromisoformat(completed_at_str)
            except (ValueError, TypeError):
                pass

        # Parse total amount
        total_str = order_data.get("total", "0")
        try:
            total_euros = float(str(total_str).split()[0])
            total_amount_cents = euros_to_cents(total_euros)
        except (ValueError, IndexError):
            total_amount_cents = 0

        # Map Letzshop state to status
        letzshop_state = shipment_data.get("state", "unconfirmed")
        status_mapping = {
            "unconfirmed": "pending",
            "confirmed": "processing",
            "declined": "cancelled",
        }
        status = status_mapping.get(letzshop_state, "pending")

        # Parse tracking info if available
        tracking_data = shipment_data.get("tracking") or {}
        tracking_number = tracking_data.get("code") or tracking_data.get("number")
        tracking_provider = tracking_data.get("provider")
        if not tracking_provider and tracking_data.get("carrier"):
            carrier = tracking_data.get("carrier", {})
            tracking_provider = carrier.get("code") or carrier.get("name")

        # Parse shipment number and carrier
        shipment_number = shipment_data.get("number")
        shipping_carrier = None
        shipment_data_obj = shipment_data.get("data") or {}
        if shipment_data_obj:
            shipping_carrier = shipment_data_obj.get("__typename", "").lower()

        # Find or create customer (inactive)
        customer = self.find_or_create_customer(
            db=db,
            store_id=store_id,
            email=customer_email,
            first_name=ship_first_name,
            last_name=ship_last_name,
            is_active=False,
        )

        # Create order
        order = Order(
            store_id=store_id,
            customer_id=customer.id,
            order_number=order_number,
            channel="letzshop",
            external_order_id=order_data.get("id"),
            external_shipment_id=shipment_data.get("id"),
            external_order_number=letzshop_order_number,
            external_data=shipment_data,
            status=status,
            total_amount_cents=total_amount_cents,
            currency="EUR",
            customer_first_name=ship_first_name,
            customer_last_name=ship_last_name,
            customer_email=customer_email,
            customer_locale=order_data.get("locale"),
            ship_first_name=ship_first_name,
            ship_last_name=ship_last_name,
            ship_company=ship_address.get("company"),
            ship_address_line_1=ship_address.get("streetName", "") or "",
            ship_address_line_2=ship_address.get("streetNumber"),
            ship_city=ship_address.get("city", "") or "",
            ship_postal_code=ship_address.get("postalCode", "") or "",
            ship_country_iso=ship_country.get("iso", "") or "",
            bill_first_name=bill_address.get("firstName", "") or ship_first_name,
            bill_last_name=bill_address.get("lastName", "") or ship_last_name,
            bill_company=bill_address.get("company"),
            bill_address_line_1=bill_address.get("streetName", "") or "",
            bill_address_line_2=bill_address.get("streetNumber"),
            bill_city=bill_address.get("city", "") or "",
            bill_postal_code=bill_address.get("postalCode", "") or "",
            bill_country_iso=bill_country.get("iso", "") or "",
            order_date=order_date,
            confirmed_at=datetime.now(UTC) if status == "processing" else None,
            cancelled_at=datetime.now(UTC) if status == "cancelled" else None,
            tracking_number=tracking_number,
            tracking_provider=tracking_provider,
            shipment_number=shipment_number,
            shipping_carrier=shipping_carrier,
        )

        db.add(order)
        db.flush()

        # Create order items from inventory units
        exceptions_created = 0
        for unit in inventory_units:
            variant = unit.get("variant", {}) or {}
            product_info = variant.get("product", {}) or {}
            trade_id = variant.get("tradeId", {}) or {}
            product_name_dict = product_info.get("name", {}) or {}

            gtin = trade_id.get("number")
            gtin_type = trade_id.get("parser")

            # Get product from map, or use placeholder if not found
            product = products_by_gtin.get(gtin)
            needs_product_match = False

            if not product:
                product = placeholder
                needs_product_match = True

            # Get product name from marketplace data
            product_name = (
                product_name_dict.get("en")
                or product_name_dict.get("fr")
                or product_name_dict.get("de")
                or str(product_name_dict)
            )

            # Get price
            unit_price_cents = 0
            price_str = variant.get("price", "0")
            try:
                price_euros = float(str(price_str).split()[0])
                unit_price_cents = euros_to_cents(price_euros)
            except (ValueError, IndexError):
                pass

            item_state = unit.get("state")

            order_item = OrderItem(
                order_id=order.id,
                product_id=product.id if product else None,
                product_name=product_name,
                product_sku=variant.get("sku"),
                gtin=gtin,
                gtin_type=gtin_type,
                quantity=1,
                unit_price_cents=unit_price_cents,
                total_price_cents=unit_price_cents,
                external_item_id=unit.get("id"),
                external_variant_id=variant.get("id"),
                item_state=item_state,
                needs_product_match=needs_product_match,
            )
            db.add(order_item)  # noqa: PERF006
            db.flush()

            # Create exception record for unmatched items
            if needs_product_match:
                order_item_exception_service.create_exception(
                    db=db,
                    order_item=order_item,
                    store_id=store_id,
                    original_gtin=gtin,
                    original_product_name=product_name,
                    original_sku=variant.get("sku"),
                    exception_type="product_not_found",
                )
                exceptions_created += 1

        db.flush()
        db.refresh(order)

        if exceptions_created > 0:
            logger.info(
                f"Created {exceptions_created} order item exception(s) for "
                f"order {order.order_number}"
            )

        # Increment order count for subscription tracking
        subscription_service.increment_order_count(db, store_id)

        logger.info(
            f"Letzshop order {order.order_number} created for store {store_id}, "
            f"status: {status}, items: {len(inventory_units)}"
        )

        return order

    # =========================================================================
    # Order Retrieval
    # =========================================================================

    def get_order(self, db: Session, store_id: int, order_id: int) -> Order:
        """Get order by ID within store scope."""
        order = (
            db.query(Order)
            .filter(and_(Order.id == order_id, Order.store_id == store_id))
            .first()
        )

        if not order:
            raise OrderNotFoundException(str(order_id))

        return order

    def get_order_by_external_shipment_id(
        self,
        db: Session,
        store_id: int,
        shipment_id: str,
    ) -> Order | None:
        """Get order by external shipment ID (for Letzshop)."""
        return (
            db.query(Order)
            .filter(
                and_(
                    Order.store_id == store_id,
                    Order.external_shipment_id == shipment_id,
                )
            )
            .first()
        )

    def get_store_orders(
        self,
        db: Session,
        store_id: int,
        skip: int = 0,
        limit: int = 50,
        status: str | None = None,
        channel: str | None = None,
        search: str | None = None,
        customer_id: int | None = None,
    ) -> tuple[list[Order], int]:
        """Get orders for store with filtering."""
        query = db.query(Order).filter(Order.store_id == store_id)

        if status:
            query = query.filter(Order.status == status)

        if channel:
            query = query.filter(Order.channel == channel)

        if customer_id:
            query = query.filter(Order.customer_id == customer_id)

        if search:
            search_term = f"%{search}%"
            query = query.filter(
                or_(
                    Order.order_number.ilike(search_term),
                    Order.external_order_number.ilike(search_term),
                    Order.customer_email.ilike(search_term),
                    Order.customer_first_name.ilike(search_term),
                    Order.customer_last_name.ilike(search_term),
                )
            )

        # Order by most recent first
        query = query.order_by(Order.order_date.desc())

        total = query.count()
        orders = query.offset(skip).limit(limit).all()

        return orders, total

    def get_customer_orders(
        self,
        db: Session,
        store_id: int,
        customer_id: int,
        skip: int = 0,
        limit: int = 50,
    ) -> tuple[list[Order], int]:
        """Get orders for a specific customer."""
        return self.get_store_orders(
            db=db,
            store_id=store_id,
            skip=skip,
            limit=limit,
            customer_id=customer_id,
        )

    def get_order_stats(self, db: Session, store_id: int) -> dict[str, int]:
        """Get order counts by status for a store."""
        status_counts = (
            db.query(Order.status, func.count(Order.id).label("count"))
            .filter(Order.store_id == store_id)
            .group_by(Order.status)
            .all()
        )

        stats = {
            "pending": 0,
            "processing": 0,
            "partially_shipped": 0,
            "shipped": 0,
            "delivered": 0,
            "cancelled": 0,
            "refunded": 0,
            "total": 0,
        }

        for status, count in status_counts:
            if status in stats:
                stats[status] = count
            stats["total"] += count

        # Also count by channel
        channel_counts = (
            db.query(Order.channel, func.count(Order.id).label("count"))
            .filter(Order.store_id == store_id)
            .group_by(Order.channel)
            .all()
        )

        for channel, count in channel_counts:
            stats[f"{channel}_orders"] = count

        return stats

    # =========================================================================
    # Order Updates
    # =========================================================================

    def update_order_status(
        self,
        db: Session,
        store_id: int,
        order_id: int,
        order_update: OrderUpdate,
    ) -> Order:
        """Update order status and tracking information."""
        from app.modules.orders.services.order_inventory_service import (
            order_inventory_service,
        )

        order = self.get_order(db, store_id, order_id)

        now = datetime.now(UTC)
        old_status = order.status

        if order_update.status:
            order.status = order_update.status

            # Update timestamps based on status
            if order_update.status == "processing" and not order.confirmed_at:
                order.confirmed_at = now
            elif order_update.status == "shipped" and not order.shipped_at:
                order.shipped_at = now
            elif order_update.status == "delivered" and not order.delivered_at:
                order.delivered_at = now
            elif order_update.status == "cancelled" and not order.cancelled_at:
                order.cancelled_at = now

            # Handle inventory operations based on status change
            try:
                inventory_result = order_inventory_service.handle_status_change(
                    db=db,
                    store_id=store_id,
                    order_id=order_id,
                    old_status=old_status,
                    new_status=order_update.status,
                )
                if inventory_result:
                    logger.info(
                        f"Order {order.order_number} inventory update: "
                        f"{inventory_result.get('reserved_count', 0)} reserved, "
                        f"{inventory_result.get('fulfilled_count', 0)} fulfilled, "
                        f"{inventory_result.get('released_count', 0)} released"
                    )
            except Exception as e:  # noqa: EXC003
                logger.warning(
                    f"Order {order.order_number} inventory operation failed: {e}"
                )

        if order_update.tracking_number:
            order.tracking_number = order_update.tracking_number

        if order_update.tracking_provider:
            order.tracking_provider = order_update.tracking_provider

        if order_update.internal_notes:
            order.internal_notes = order_update.internal_notes

        order.updated_at = now
        db.flush()
        db.refresh(order)

        logger.info(f"Order {order.order_number} updated: status={order.status}")

        return order

    def set_order_tracking(
        self,
        db: Session,
        store_id: int,
        order_id: int,
        tracking_number: str,
        tracking_provider: str,
    ) -> Order:
        """Set tracking information and mark as shipped."""
        order = self.get_order(db, store_id, order_id)

        now = datetime.now(UTC)
        order.tracking_number = tracking_number
        order.tracking_provider = tracking_provider
        order.status = "shipped"
        order.shipped_at = now
        order.updated_at = now

        db.flush()
        db.refresh(order)

        logger.info(
            f"Order {order.order_number} shipped: "
            f"{tracking_provider} {tracking_number}"
        )

        return order

    def update_item_state(
        self,
        db: Session,
        store_id: int,
        order_id: int,
        item_id: int,
        state: str,
    ) -> OrderItem:
        """Update the state of an order item (for marketplace confirmation)."""
        order = self.get_order(db, store_id, order_id)

        item = (
            db.query(OrderItem)
            .filter(
                and_(
                    OrderItem.id == item_id,
                    OrderItem.order_id == order.id,
                )
            )
            .first()
        )

        if not item:
            raise OrderValidationException(f"Order item {item_id} not found")

        item.item_state = state
        item.updated_at = datetime.now(UTC)

        # Check if all items are processed
        all_items = db.query(OrderItem).filter(OrderItem.order_id == order.id).all()
        all_confirmed = all(
            i.item_state in ("confirmed_available", "confirmed_unavailable")
            for i in all_items
        )

        if all_confirmed:
            has_available = any(
                i.item_state == "confirmed_available" for i in all_items
            )
            all_unavailable = all(
                i.item_state == "confirmed_unavailable" for i in all_items
            )

            now = datetime.now(UTC)
            if all_unavailable:
                order.status = "cancelled"
                order.cancelled_at = now
            elif has_available:
                order.status = "processing"
                order.confirmed_at = now

            order.updated_at = now

        db.flush()
        db.refresh(item)

        return item

    # =========================================================================
    # Admin Methods (cross-store)
    # =========================================================================

    def get_all_orders_admin(
        self,
        db: Session,
        skip: int = 0,
        limit: int = 50,
        store_id: int | None = None,
        status: str | None = None,
        channel: str | None = None,
        search: str | None = None,
    ) -> tuple[list[dict], int]:
        """Get orders across all stores for admin."""
        from sqlalchemy.orm import joinedload
        query = db.query(Order).options(joinedload(Order.store))

        if store_id:
            query = query.filter(Order.store_id == store_id)

        if status:
            query = query.filter(Order.status == status)

        if channel:
            query = query.filter(Order.channel == channel)

        if search:
            search_term = f"%{search}%"
            query = query.filter(
                or_(
                    Order.order_number.ilike(search_term),
                    Order.external_order_number.ilike(search_term),
                    Order.customer_email.ilike(search_term),
                    Order.customer_first_name.ilike(search_term),
                    Order.customer_last_name.ilike(search_term),
                )
            )

        query = query.order_by(Order.order_date.desc())

        total = query.count()
        orders = query.offset(skip).limit(limit).all()

        result = []
        for order in orders:
            item_count = len(order.items) if order.items else 0

            result.append(
                {
                    "id": order.id,
                    "store_id": order.store_id,
                    "store_name": order.store.name if order.store else None,
                    "store_code": order.store.store_code if order.store else None,
                    "customer_id": order.customer_id,
                    "customer_full_name": order.customer_full_name,
                    "customer_email": order.customer_email,
                    "order_number": order.order_number,
                    "channel": order.channel,
                    "status": order.status,
                    "external_order_number": order.external_order_number,
                    "external_shipment_id": order.external_shipment_id,
                    "subtotal": order.subtotal,
                    "tax_amount": order.tax_amount,
                    "shipping_amount": order.shipping_amount,
                    "discount_amount": order.discount_amount,
                    "total_amount": order.total_amount,
                    "currency": order.currency,
                    "ship_country_iso": order.ship_country_iso,
                    "tracking_number": order.tracking_number,
                    "tracking_provider": order.tracking_provider,
                    "item_count": item_count,
                    "order_date": order.order_date,
                    "confirmed_at": order.confirmed_at,
                    "shipped_at": order.shipped_at,
                    "delivered_at": order.delivered_at,
                    "cancelled_at": order.cancelled_at,
                    "created_at": order.created_at,
                    "updated_at": order.updated_at,
                }
            )

        return result, total

    def get_order_stats_admin(self, db: Session) -> dict:
        """Get platform-wide order statistics."""
        # Get status counts
        status_counts = (
            db.query(Order.status, func.count(Order.id))
            .group_by(Order.status)
            .all()
        )

        stats = {
            "total_orders": 0,
            "pending_orders": 0,
            "processing_orders": 0,
            "partially_shipped_orders": 0,
            "shipped_orders": 0,
            "delivered_orders": 0,
            "cancelled_orders": 0,
            "refunded_orders": 0,
            "total_revenue": 0.0,
            "direct_orders": 0,
            "letzshop_orders": 0,
            "stores_with_orders": 0,
        }

        for status, count in status_counts:
            stats["total_orders"] += count
            key = f"{status}_orders"
            if key in stats:
                stats[key] = count

        # Get channel counts
        channel_counts = (
            db.query(Order.channel, func.count(Order.id))
            .group_by(Order.channel)
            .all()
        )

        for channel, count in channel_counts:
            key = f"{channel}_orders"
            if key in stats:
                stats[key] = count

        # Get total revenue
        revenue_cents = (
            db.query(func.sum(Order.total_amount_cents))
            .filter(Order.status == "delivered")
            .scalar()
        )
        stats["total_revenue"] = cents_to_euros(revenue_cents) if revenue_cents else 0.0

        # Count stores with orders
        stores_count = (
            db.query(func.count(func.distinct(Order.store_id))).scalar() or 0
        )
        stats["stores_with_orders"] = stores_count

        return stats

    def get_order_by_id_admin(self, db: Session, order_id: int) -> Order:
        """Get order by ID without store scope (admin only)."""
        order = db.query(Order).filter(Order.id == order_id).first()

        if not order:
            raise OrderNotFoundException(str(order_id))

        return order

    def get_stores_with_orders_admin(self, db: Session) -> list[dict]:
        """Get list of stores that have orders (admin only)."""
        from app.modules.tenancy.services.store_service import store_service

        # Get store IDs with order counts
        store_order_counts = (
            db.query(
                Order.store_id,
                func.count(Order.id).label("order_count"),
            )
            .group_by(Order.store_id)
            .order_by(func.count(Order.id).desc())
            .all()
        )

        result = []
        for store_id, order_count in store_order_counts:
            store = store_service.get_store_by_id_optional(db, store_id)
            if store:
                result.append({
                    "id": store.id,
                    "name": store.name,
                    "store_code": store.store_code,
                    "order_count": order_count,
                })

        return result

    def mark_as_shipped_admin(
        self,
        db: Session,
        order_id: int,
        tracking_number: str | None = None,
        tracking_url: str | None = None,
        shipping_carrier: str | None = None,
    ) -> Order:
        """Mark an order as shipped with optional tracking info (admin only)."""
        order = db.query(Order).filter(Order.id == order_id).first()

        if not order:
            raise OrderNotFoundException(str(order_id))

        order.status = "shipped"
        order.shipped_at = datetime.now(UTC)
        order.updated_at = datetime.now(UTC)

        if tracking_number:
            order.tracking_number = tracking_number
        if tracking_url:
            order.tracking_url = tracking_url
        if shipping_carrier:
            order.shipping_carrier = shipping_carrier

        logger.info(
            f"Order {order.order_number} marked as shipped. "
            f"Tracking: {tracking_number or 'N/A'}, Carrier: {shipping_carrier or 'N/A'}"
        )

        return order

    def get_shipping_label_info_admin(
        self,
        db: Session,
        order_id: int,
    ) -> dict[str, Any]:
        """Get shipping label information for an order (admin only)."""
        from app.modules.core.services.admin_settings_service import (
            admin_settings_service,  # MOD-004
        )

        order = db.query(Order).filter(Order.id == order_id).first()

        if not order:
            raise OrderNotFoundException(str(order_id))

        label_url = None
        carrier = order.shipping_carrier

        # Generate label URL based on carrier
        if order.shipment_number and carrier:
            setting_key = f"carrier_{carrier}_label_url"
            prefix = admin_settings_service.get_setting_value(db, setting_key)

            if prefix:
                label_url = prefix + order.shipment_number

        return {
            "shipment_number": order.shipment_number,
            "shipping_carrier": carrier,
            "label_url": label_url,
            "tracking_number": order.tracking_number,
            "tracking_url": order.tracking_url,
        }


    # ========================================================================
    # Cross-module public API methods
    # ========================================================================

    def get_order_by_id(
        self, db: Session, order_id: int, store_id: int | None = None
    ) -> Order | None:
        """
        Get order by ID, optionally scoped to a store.

        Args:
            db: Database session
            order_id: Order ID
            store_id: Optional store scope

        Returns:
            Order object or None
        """
        query = db.query(Order).filter(Order.id == order_id)
        if store_id is not None:
            query = query.filter(Order.store_id == store_id)
        return query.first()

    def get_store_order_count(self, db: Session, store_id: int) -> int:
        """
        Count orders for a store.

        Args:
            db: Database session
            store_id: Store ID

        Returns:
            Order count
        """
        return (
            db.query(func.count(Order.id))
            .filter(Order.store_id == store_id)
            .scalar()
            or 0
        )

    def get_total_order_count(
        self, db: Session, date_from: "datetime | None" = None
    ) -> int:
        """
        Get total order count, optionally filtered by date.

        Args:
            db: Database session
            date_from: Optional start date filter

        Returns:
            Total order count
        """
        query = db.query(func.count(Order.id))
        if date_from is not None:
            query = query.filter(Order.created_at >= date_from)
        return query.scalar() or 0


# Create service instance
order_service = OrderService()
