# app/services/letzshop/order_service.py
"""
Letzshop order service for handling order-related database operations.

This service handles Letzshop-specific order operations while using the
unified Order model. All Letzshop orders are stored in the `orders` table
with `channel='letzshop'`.
"""

from __future__ import annotations

import logging
from collections.abc import Callable
from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any

from sqlalchemy import func, or_
from sqlalchemy.orm import Session

from app.modules.billing.services.subscription_service import subscription_service
from app.modules.marketplace.models import (
    LetzshopFulfillmentQueue,
    LetzshopHistoricalImportJob,
    LetzshopSyncLog,
    MarketplaceImportJob,
    StoreLetzshopCredentials,
)
from app.modules.orders.services.order_service import (
    order_service as unified_order_service,
)

if TYPE_CHECKING:
    from app.modules.catalog.models import Product
    from app.modules.orders.models import Order, OrderItem
    from app.modules.tenancy.models import Store

logger = logging.getLogger(__name__)


class StoreNotFoundError(Exception):
    """Raised when a store is not found."""


class OrderNotFoundError(Exception):
    """Raised when an order is not found."""


def _get_order_models():
    """Deferred import for Order/OrderItem models (orders module)."""
    from app.modules.orders.models import Order, OrderItem

    return Order, OrderItem


class LetzshopOrderService:
    """Service for Letzshop order database operations using unified Order model."""

    def __init__(self, db: Session):
        self.db = db
        self._Order, self._OrderItem = _get_order_models()

    # =========================================================================
    # Store Operations
    # =========================================================================

    def get_store(self, store_id: int) -> Store | None:
        """Get store by ID."""
        from app.modules.tenancy.services.store_service import store_service

        return store_service.get_store_by_id_optional(self.db, store_id)

    def get_store_or_raise(self, store_id: int) -> Store:
        """Get store by ID or raise StoreNotFoundError."""
        store = self.get_store(store_id)
        if store is None:
            raise StoreNotFoundError(f"Store with ID {store_id} not found")
        return store

    def list_stores_with_letzshop_status(
        self,
        skip: int = 0,
        limit: int = 100,
        configured_only: bool = False,
    ) -> tuple[list[dict[str, Any]], int]:
        """
        List stores with their Letzshop integration status.

        Returns a tuple of (store_overviews, total_count).
        """
        from app.modules.tenancy.services.store_service import store_service as _ss

        all_stores = _ss.list_all_stores(self.db, active_only=True)

        if configured_only:
            # Filter to stores that have credentials
            cred_store_ids = {
                c.store_id
                for c in self.db.query(StoreLetzshopCredentials.store_id).all()
            }
            all_stores = [s for s in all_stores if s.id in cred_store_ids]

        all_stores.sort(key=lambda s: s.name or "")
        total = len(all_stores)
        stores = all_stores[skip : skip + limit]

        store_overviews = []
        for store in stores:
            credentials = (
                self.db.query(StoreLetzshopCredentials)
                .filter(StoreLetzshopCredentials.store_id == store.id)
                .first()
            )

            # Count Letzshop orders from unified orders table
            pending_orders = 0
            total_orders = 0
            if credentials:
                pending_orders = (
                    self.db.query(func.count(self._Order.id))
                    .filter(
                        self._Order.store_id == store.id,
                        self._Order.channel == "letzshop",
                        self._Order.status == "pending",
                    )
                    .scalar()
                    or 0
                )
                total_orders = (
                    self.db.query(func.count(self._Order.id))
                    .filter(
                        self._Order.store_id == store.id,
                        self._Order.channel == "letzshop",
                    )
                    .scalar()
                    or 0
                )

            store_overviews.append(
                {
                    "store_id": store.id,
                    "store_name": store.name,
                    "store_code": store.store_code,
                    "is_configured": credentials is not None,
                    "auto_sync_enabled": credentials.auto_sync_enabled
                    if credentials
                    else False,
                    "last_sync_at": credentials.last_sync_at if credentials else None,
                    "last_sync_status": credentials.last_sync_status
                    if credentials
                    else None,
                    "pending_orders": pending_orders,
                    "total_orders": total_orders,
                }
            )

        return store_overviews, total

    # =========================================================================
    # Order Operations (using unified Order model)
    # =========================================================================

    def get_order(self, store_id: int, order_id: int) -> Order | None:
        """Get a Letzshop order by ID for a specific store."""
        return (
            self.db.query(self._Order)
            .filter(
                self._Order.id == order_id,
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
            )
            .first()
        )

    def get_order_or_raise(self, store_id: int, order_id: int) -> Order:
        """Get a Letzshop order or raise OrderNotFoundError."""
        order = self.get_order(store_id, order_id)
        if order is None:
            raise OrderNotFoundError(f"Order {order_id} not found")
        return order

    def get_order_by_shipment_id(
        self, store_id: int, shipment_id: str
    ) -> Order | None:
        """Get a Letzshop order by external shipment ID."""
        return (
            self.db.query(self._Order)
            .filter(
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
                self._Order.external_shipment_id == shipment_id,
            )
            .first()
        )

    def get_order_by_id(self, order_id: int) -> Order | None:
        """Get a Letzshop order by its database ID."""
        return (
            self.db.query(self._Order)
            .filter(
                self._Order.id == order_id,
                self._Order.channel == "letzshop",
            )
            .first()
        )

    def list_orders(
        self,
        store_id: int | None = None,
        skip: int = 0,
        limit: int = 50,
        status: str | None = None,
        has_declined_items: bool | None = None,
        search: str | None = None,
    ) -> tuple[list[Order], int]:
        """
        List Letzshop orders for a store (or all stores).

        Args:
            store_id: Store ID to filter by. If None, returns all stores.
            skip: Number of records to skip.
            limit: Maximum number of records to return.
            status: Filter by order status (pending, processing, shipped, etc.)
            has_declined_items: If True, only return orders with declined items.
            search: Search by order number, customer name, or email.

        Returns a tuple of (orders, total_count).
        """
        query = self.db.query(self._Order).filter(
            self._Order.channel == "letzshop",
        )

        # Filter by store if specified
        if store_id is not None:
            query = query.filter(self._Order.store_id == store_id)

        if status:
            query = query.filter(self._Order.status == status)

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

        # Filter for orders with declined items
        if has_declined_items is True:
            # Subquery to find orders with declined items
            declined_order_ids = (
                self.db.query(self._OrderItem.order_id)
                .filter(self._OrderItem.item_state == "confirmed_unavailable")
                .subquery()
            )
            query = query.filter(self._Order.id.in_(declined_order_ids))

        total = query.count()
        orders = (
            query.order_by(self._Order.order_date.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )

        return orders, total

    def get_order_stats(self, store_id: int | None = None) -> dict[str, int]:
        """
        Get order counts by status for Letzshop orders.

        Args:
            store_id: Store ID to filter by. If None, returns stats for all stores.

        Returns:
            Dict with counts for each status.
        """
        query = self.db.query(
            self._Order.status,
            func.count(self._Order.id).label("count"),
        ).filter(self._Order.channel == "letzshop")

        if store_id is not None:
            query = query.filter(self._Order.store_id == store_id)

        status_counts = query.group_by(self._Order.status).all()

        stats = {
            "pending": 0,
            "processing": 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

        # Count orders with declined items
        declined_query = (
            self.db.query(func.count(func.distinct(self._OrderItem.order_id)))
            .join(Order, self._OrderItem.order_id == self._Order.id)
            .filter(
                self._Order.channel == "letzshop",
                self._OrderItem.item_state == "confirmed_unavailable",
            )
        )
        if store_id is not None:
            declined_query = declined_query.filter(self._Order.store_id == store_id)

        stats["has_declined_items"] = declined_query.scalar() or 0

        return stats

    def create_order(
        self,
        store_id: int,
        shipment_data: dict[str, Any],
    ) -> Order:
        """
        Create a new Letzshop order from shipment data.

        Uses the unified order service to create the order.
        """
        return unified_order_service.create_letzshop_order(
            db=self.db,
            store_id=store_id,
            shipment_data=shipment_data,
        )

    def update_order_from_shipment(
        self,
        order: Order,
        shipment_data: dict[str, Any],
    ) -> Order:
        """Update an existing order from shipment data."""
        order_data = shipment_data.get("order", {})

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

        # Update status if changed
        if order.status != new_status:
            order.status = new_status
            now = datetime.now(UTC)
            if new_status == "processing":
                order.confirmed_at = now
            elif new_status == "cancelled":
                order.cancelled_at = now

        # Update external data
        order.external_data = shipment_data

        # Update locale if not set
        if not order.customer_locale and order_data.get("locale"):
            order.customer_locale = order_data.get("locale")

        # Update order_date if not set
        if not order.order_date:
            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.order_date = datetime.fromisoformat(completed_at_str)
                except (ValueError, TypeError):
                    pass

        # Update inventory unit states in order items
        inventory_units_data = shipment_data.get("inventoryUnits", [])
        if isinstance(inventory_units_data, dict):
            inventory_units_data = inventory_units_data.get("nodes", [])

        for unit in inventory_units_data:
            unit_id = unit.get("id")
            unit_state = unit.get("state")
            if unit_id and unit_state:
                # Find and update the corresponding order item
                item = (
                    self.db.query(self._OrderItem)
                    .filter(
                        self._OrderItem.order_id == order.id,
                        self._OrderItem.external_item_id == unit_id,
                    )
                    .first()
                )
                if item:
                    item.item_state = unit_state

        order.updated_at = datetime.now(UTC)
        return order

    def mark_order_confirmed(self, order: Order) -> Order:
        """Mark an order as confirmed (processing)."""
        order.confirmed_at = datetime.now(UTC)
        order.status = "processing"
        order.updated_at = datetime.now(UTC)
        return order

    def mark_order_rejected(self, order: Order) -> Order:
        """Mark an order as rejected (cancelled)."""
        order.cancelled_at = datetime.now(UTC)
        order.status = "cancelled"
        order.updated_at = datetime.now(UTC)
        return order

    def update_inventory_unit_state(
        self, order: Order, item_id: str, state: str
    ) -> Order:
        """
        Update the state of a single order item.

        Args:
            order: The order containing the item.
            item_id: The external item ID (Letzshop inventory unit ID).
            state: The new state (confirmed_available, confirmed_unavailable).

        Returns:
            The updated order.
        """
        # Find and update the item
        item = (
            self.db.query(self._OrderItem)
            .filter(
                self._OrderItem.order_id == order.id,
                self._OrderItem.external_item_id == item_id,
            )
            .first()
        )

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

        # Check if all items are now processed
        all_items = (
            self.db.query(self._OrderItem)
            .filter(self._OrderItem.order_id == order.id)
            .all()
        )

        all_confirmed = all(
            i.item_state in ("confirmed_available", "confirmed_unavailable", "returned")
            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

        return order

    def set_order_tracking(
        self,
        order: Order,
        tracking_number: str,
        tracking_provider: str,
    ) -> Order:
        """Set tracking information for an order."""
        order.tracking_number = tracking_number
        order.tracking_provider = tracking_provider
        order.shipped_at = datetime.now(UTC)
        order.status = "shipped"
        order.updated_at = datetime.now(UTC)
        return order

    def get_orders_without_tracking(
        self,
        store_id: int,
        limit: int = 100,
    ) -> list[Order]:
        """Get orders that have been confirmed but don't have tracking info."""
        return (
            self.db.query(self._Order)
            .filter(
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
                self._Order.status == "processing",  # Confirmed orders
                self._Order.tracking_number.is_(None),
                self._Order.external_shipment_id.isnot(None),  # Has shipment ID
            )
            .limit(limit)
            .all()
        )

    def update_tracking_from_shipment_data(
        self,
        order: Order,
        shipment_data: dict[str, Any],
    ) -> bool:
        """
        Update order tracking from Letzshop shipment data.

        Args:
            order: The order to update.
            shipment_data: Raw shipment data from Letzshop API.

        Returns:
            True if tracking was updated, False otherwise.
        """
        tracking_data = shipment_data.get("tracking") or {}
        tracking_number = tracking_data.get("code") or tracking_data.get("number")

        if not tracking_number:
            return False

        tracking_provider = tracking_data.get("provider")
        # Handle carrier object format: tracking { carrier { name code } }
        if not tracking_provider and tracking_data.get("carrier"):
            carrier = tracking_data.get("carrier", {})
            tracking_provider = carrier.get("code") or carrier.get("name")

        order.tracking_number = tracking_number
        order.tracking_provider = tracking_provider
        order.updated_at = datetime.now(UTC)

        logger.info(
            f"Updated tracking for order {order.order_number}: "
            f"{tracking_provider} {tracking_number}"
        )
        return True

    def get_order_items(self, order: Order) -> list[OrderItem]:
        """Get all items for an order."""
        return (
            self.db.query(self._OrderItem)
            .filter(self._OrderItem.order_id == order.id)
            .all()
        )

    # =========================================================================
    # Sync Log Operations
    # =========================================================================

    def list_sync_logs(
        self,
        store_id: int,
        skip: int = 0,
        limit: int = 50,
    ) -> tuple[list[LetzshopSyncLog], int]:
        """List sync logs for a store."""
        query = self.db.query(LetzshopSyncLog).filter(
            LetzshopSyncLog.store_id == store_id
        )
        total = query.count()
        logs = (
            query.order_by(LetzshopSyncLog.started_at.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )
        return logs, total

    # =========================================================================
    # Fulfillment Queue Operations
    # =========================================================================

    def list_fulfillment_queue(
        self,
        store_id: int,
        skip: int = 0,
        limit: int = 50,
        status: str | None = None,
    ) -> tuple[list[LetzshopFulfillmentQueue], int]:
        """List fulfillment queue items for a store."""
        query = self.db.query(LetzshopFulfillmentQueue).filter(
            LetzshopFulfillmentQueue.store_id == store_id
        )

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

        total = query.count()
        items = (
            query.order_by(LetzshopFulfillmentQueue.created_at.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )
        return items, total

    def add_to_fulfillment_queue(
        self,
        store_id: int,
        order_id: int,
        operation: str,
        payload: dict[str, Any],
    ) -> LetzshopFulfillmentQueue:
        """Add an operation to the fulfillment queue."""
        queue_item = LetzshopFulfillmentQueue(
            store_id=store_id,
            order_id=order_id,
            operation=operation,
            payload=payload,
            status="pending",
        )
        self.db.add(queue_item)
        return queue_item

    # =========================================================================
    # Unified Jobs Operations
    # =========================================================================

    def list_letzshop_jobs(
        self,
        store_id: int | None = None,
        job_type: str | None = None,
        status: str | None = None,
        skip: int = 0,
        limit: int = 20,
    ) -> tuple[list[dict[str, Any]], int]:
        """
        List unified Letzshop-related jobs for a store or all stores.

        Combines product imports, historical order imports, and order syncs.
        If store_id is None, returns jobs across all stores.
        """
        jobs = []

        # Fetch store info - for single store or build lookup for all stores
        if store_id:
            store = self.get_store(store_id)
            store_lookup = {store_id: (store.name if store else None, store.store_code if store else None)}
        else:
            # Build lookup for all stores when showing all jobs
            from app.modules.tenancy.services.store_service import store_service
            all_stores = store_service.list_all_stores(self.db)
            store_lookup = {s.id: (s.name, s.store_code) for s in all_stores}

        # Historical order imports from letzshop_historical_import_jobs
        if job_type in (None, "historical_import"):
            hist_query = self.db.query(LetzshopHistoricalImportJob)
            if store_id:
                hist_query = hist_query.filter(
                    LetzshopHistoricalImportJob.store_id == store_id,
                )
            if status:
                hist_query = hist_query.filter(
                    LetzshopHistoricalImportJob.status == status
                )

            hist_jobs = hist_query.order_by(
                LetzshopHistoricalImportJob.created_at.desc()
            ).all()

            for job in hist_jobs:
                v_name, v_code = store_lookup.get(job.store_id, (None, None))
                jobs.append(
                    {
                        "id": job.id,
                        "type": "historical_import",
                        "status": job.status,
                        "created_at": job.created_at,
                        "started_at": job.started_at,
                        "completed_at": job.completed_at,
                        "records_processed": job.orders_processed or 0,
                        "records_succeeded": (job.orders_imported or 0)
                        + (job.orders_updated or 0),
                        "records_failed": job.orders_skipped or 0,
                        "store_id": job.store_id,
                        "store_name": v_name,
                        "store_code": v_code,
                        "current_phase": job.current_phase,
                        "error_message": job.error_message,
                    }
                )

        # Product imports from marketplace_import_jobs
        if job_type in (None, "import"):
            import_query = self.db.query(MarketplaceImportJob).filter(
                MarketplaceImportJob.marketplace == "Letzshop",
            )
            if store_id:
                import_query = import_query.filter(
                    MarketplaceImportJob.store_id == store_id,
                )
            if status:
                import_query = import_query.filter(
                    MarketplaceImportJob.status == status
                )

            import_jobs = import_query.order_by(
                MarketplaceImportJob.created_at.desc()
            ).all()

            for job in import_jobs:
                v_name, v_code = store_lookup.get(job.store_id, (None, None))
                jobs.append(
                    {
                        "id": job.id,
                        "type": "import",
                        "status": job.status,
                        "created_at": job.created_at,
                        "started_at": job.started_at,
                        "completed_at": job.completed_at,
                        "records_processed": job.total_processed or 0,
                        "records_succeeded": (job.imported_count or 0)
                        + (job.updated_count or 0),
                        "records_failed": job.error_count or 0,
                        "store_id": job.store_id,
                        "store_name": v_name,
                        "store_code": v_code,
                    }
                )

        # Order syncs from letzshop_sync_logs
        if job_type in (None, "order_sync"):
            sync_query = self.db.query(LetzshopSyncLog).filter(
                LetzshopSyncLog.operation_type == "order_import",
            )
            if store_id:
                sync_query = sync_query.filter(LetzshopSyncLog.store_id == store_id)
            if status:
                sync_query = sync_query.filter(LetzshopSyncLog.status == status)

            sync_logs = sync_query.order_by(LetzshopSyncLog.created_at.desc()).all()

            for log in sync_logs:
                v_name, v_code = store_lookup.get(log.store_id, (None, None))
                jobs.append(
                    {
                        "id": log.id,
                        "type": "order_sync",
                        "status": log.status,
                        "created_at": log.created_at,
                        "started_at": log.started_at,
                        "completed_at": log.completed_at,
                        "records_processed": log.records_processed or 0,
                        "records_succeeded": log.records_succeeded or 0,
                        "records_failed": log.records_failed or 0,
                        "store_id": log.store_id,
                        "store_name": v_name,
                        "store_code": v_code,
                        "error_details": log.error_details,
                    }
                )

        # Product exports from letzshop_sync_logs
        if job_type in (None, "export"):
            export_query = self.db.query(LetzshopSyncLog).filter(
                LetzshopSyncLog.operation_type == "product_export",
            )
            if store_id:
                export_query = export_query.filter(LetzshopSyncLog.store_id == store_id)
            if status:
                export_query = export_query.filter(LetzshopSyncLog.status == status)

            export_logs = export_query.order_by(
                LetzshopSyncLog.created_at.desc()
            ).all()

            for log in export_logs:
                v_name, v_code = store_lookup.get(log.store_id, (None, None))
                jobs.append(
                    {
                        "id": log.id,
                        "type": "export",
                        "status": log.status,
                        "created_at": log.created_at,
                        "started_at": log.started_at,
                        "completed_at": log.completed_at,
                        "records_processed": log.records_processed or 0,
                        "records_succeeded": log.records_succeeded or 0,
                        "records_failed": log.records_failed or 0,
                        "store_id": log.store_id,
                        "store_name": v_name,
                        "store_code": v_code,
                        "error_details": log.error_details,
                    }
                )

        # Sort all jobs by created_at descending
        jobs.sort(key=lambda x: x["created_at"], reverse=True)

        total = len(jobs)
        jobs = jobs[skip : skip + limit]

        return jobs, total

    # =========================================================================
    # Historical Import Operations
    # =========================================================================

    def import_historical_shipments(
        self,
        store_id: int,
        shipments: list[dict[str, Any]],
        match_products: bool = True,
        progress_callback: Callable[[int, int, int, int], None] | None = None,
    ) -> dict[str, Any]:
        """
        Import historical shipments into the unified orders table.

        Args:
            store_id: Store ID to import for.
            shipments: List of shipment data from Letzshop API.
            match_products: Whether to match GTIN to local products.
            progress_callback: Optional callback(processed, imported, updated, skipped)

        Returns:
            Dict with import statistics.
        """
        stats = {
            "total": len(shipments),
            "imported": 0,
            "updated": 0,
            "skipped": 0,
            "errors": 0,
            "limit_exceeded": 0,
            "products_matched": 0,
            "products_not_found": 0,
            "eans_processed": set(),
            "eans_matched": set(),
            "eans_not_found": set(),
            "error_messages": [],
        }

        # Get subscription usage upfront for batch efficiency
        usage = subscription_service.get_usage(self.db, store_id)
        orders_remaining = usage.orders_remaining  # None = unlimited

        for i, shipment in enumerate(shipments):
            shipment_id = shipment.get("id")
            if not shipment_id:
                continue

            # Check if order already exists
            existing_order = self.get_order_by_shipment_id(store_id, shipment_id)

            if existing_order:
                # Check if we need to update
                letzshop_state = shipment.get("state")
                state_mapping = {
                    "unconfirmed": "pending",
                    "confirmed": "processing",
                    "declined": "cancelled",
                }
                expected_status = state_mapping.get(letzshop_state, "processing")

                needs_update = False
                if existing_order.status != expected_status:
                    self.update_order_from_shipment(existing_order, shipment)
                    needs_update = True

                # Update order_date if missing
                if not existing_order.order_date:
                    order_data = shipment.get("order", {})
                    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"
                            existing_order.order_date = datetime.fromisoformat(
                                completed_at_str
                            )
                            needs_update = True
                        except (ValueError, TypeError):
                            pass

                if needs_update:
                    self.db.commit()  # SVC-006 - background task needs incremental commits
                    stats["updated"] += 1
                else:
                    stats["skipped"] += 1
            else:
                # Check tier limit before creating order
                if orders_remaining is not None and orders_remaining <= 0:
                    stats["limit_exceeded"] += 1
                    stats["error_messages"].append(
                        f"Shipment {shipment_id}: Order limit reached"
                    )
                    continue

                # Create new order using unified service
                try:
                    self.create_order(store_id, shipment)
                    self.db.commit()  # SVC-006 - background task needs incremental commits
                    stats["imported"] += 1

                    # Decrement remaining count for batch efficiency
                    if orders_remaining is not None:
                        orders_remaining -= 1

                except Exception as e:
                    self.db.rollback()  # Rollback failed order
                    stats["errors"] += 1
                    stats["error_messages"].append(
                        f"Shipment {shipment_id}: {str(e)}"
                    )
                    logger.error(f"Error importing shipment {shipment_id}: {e}")

            # Process GTINs for matching
            if match_products:
                inventory_units = shipment.get("inventoryUnits", [])
                for unit in inventory_units:
                    variant = unit.get("variant", {}) or {}
                    trade_id = variant.get("tradeId") or {}
                    gtin = trade_id.get("number")

                    if gtin:
                        stats["eans_processed"].add(gtin)

            # Report progress
            if progress_callback and ((i + 1) % 10 == 0 or i == len(shipments) - 1):
                progress_callback(
                    i + 1,
                    stats["imported"],
                    stats["updated"],
                    stats["skipped"],
                )

        # Match GTINs to local products
        if match_products and stats["eans_processed"]:
            matched, not_found = self._match_gtins_to_products(
                store_id, list(stats["eans_processed"])
            )
            stats["eans_matched"] = matched
            stats["eans_not_found"] = not_found
            stats["products_matched"] = len(matched)
            stats["products_not_found"] = len(not_found)

        # Convert sets to lists for JSON serialization
        stats["eans_processed"] = list(stats["eans_processed"])
        stats["eans_matched"] = list(stats["eans_matched"])
        stats["eans_not_found"] = list(stats["eans_not_found"])

        return stats

    def _match_gtins_to_products(
        self,
        store_id: int,
        gtins: list[str],
    ) -> tuple[set[str], set[str]]:
        """Match GTIN codes to local products."""
        if not gtins:
            return set(), set()

        from app.modules.catalog.models import Product

        products = (
            self.db.query(Product)
            .filter(
                Product.store_id == store_id,
                Product.gtin.in_(gtins),
            )
            .all()
        )

        matched_gtins = {p.gtin for p in products if p.gtin}
        not_found_gtins = set(gtins) - matched_gtins

        logger.info(
            f"GTIN matching: {len(matched_gtins)} matched, "
            f"{len(not_found_gtins)} not found"
        )
        return matched_gtins, not_found_gtins

    def get_products_by_gtins(
        self,
        store_id: int,
        gtins: list[str],
    ) -> dict[str, Product]:
        """Get products by their GTIN codes."""
        if not gtins:
            return {}

        from app.modules.catalog.models import Product

        products = (
            self.db.query(Product)
            .filter(
                Product.store_id == store_id,
                Product.gtin.in_(gtins),
            )
            .all()
        )

        return {p.gtin: p for p in products if p.gtin}

    def get_historical_import_summary(
        self,
        store_id: int,
    ) -> dict[str, Any]:
        """Get summary of Letzshop orders for a store."""
        # Count orders by status
        status_counts = (
            self.db.query(
                self._Order.status,
                func.count(self._Order.id).label("count"),
            )
            .filter(
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
            )
            .group_by(self._Order.status)
            .all()
        )

        # Count orders by locale
        locale_counts = (
            self.db.query(
                self._Order.customer_locale,
                func.count(self._Order.id).label("count"),
            )
            .filter(
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
            )
            .group_by(self._Order.customer_locale)
            .all()
        )

        # Count orders by country
        country_counts = (
            self.db.query(
                self._Order.ship_country_iso,
                func.count(self._Order.id).label("count"),
            )
            .filter(
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
            )
            .group_by(self._Order.ship_country_iso)
            .all()
        )

        # Total orders
        total_orders = (
            self.db.query(func.count(self._Order.id))
            .filter(
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
            )
            .scalar()
            or 0
        )

        # Unique customers
        unique_customers = (
            self.db.query(func.count(func.distinct(self._Order.customer_email)))
            .filter(
                self._Order.store_id == store_id,
                self._Order.channel == "letzshop",
            )
            .scalar()
            or 0
        )

        return {
            "total_orders": total_orders,
            "unique_customers": unique_customers,
            "orders_by_status": dict(status_counts),
            "orders_by_locale": {
                locale or "unknown": count for locale, count in locale_counts
            },
            "orders_by_country": {
                country or "unknown": count for country, count in country_counts
            },
        }

    # =========================================================================
    # Historical Import Job Operations
    # =========================================================================

    def get_running_historical_import_job(
        self,
        store_id: int,
    ) -> LetzshopHistoricalImportJob | None:
        """Get any running historical import job for a store."""
        return (
            self.db.query(LetzshopHistoricalImportJob)
            .filter(
                LetzshopHistoricalImportJob.store_id == store_id,
                LetzshopHistoricalImportJob.status.in_(
                    ["pending", "fetching", "processing"]
                ),
            )
            .first()
        )

    def create_historical_import_job(
        self,
        store_id: int,
        user_id: int,
    ) -> LetzshopHistoricalImportJob:
        """Create a new historical import job."""
        job = LetzshopHistoricalImportJob(
            store_id=store_id,
            user_id=user_id,
            status="pending",
        )
        self.db.add(job)
        self.db.commit()  # SVC-006 - job must be visible immediately before background task starts
        self.db.refresh(job)
        return job

    def get_historical_import_job_by_id(
        self,
        store_id: int,
        job_id: int,
    ) -> LetzshopHistoricalImportJob | None:
        """Get a historical import job by ID."""
        return (
            self.db.query(LetzshopHistoricalImportJob)
            .filter(
                LetzshopHistoricalImportJob.id == job_id,
                LetzshopHistoricalImportJob.store_id == store_id,
            )
            .first()
        )

    def update_job_celery_task_id(
        self,
        job_id: int,
        celery_task_id: str,
    ) -> bool:
        """
        Update the Celery task ID for a historical import job.

        Args:
            job_id: The job ID to update.
            celery_task_id: The Celery task ID to set.

        Returns:
            True if updated successfully, False if job not found.
        """
        job = (
            self.db.query(LetzshopHistoricalImportJob)
            .filter(LetzshopHistoricalImportJob.id == job_id)
            .first()
        )
        if job:
            job.celery_task_id = celery_task_id
            self.db.commit()  # SVC-006 - Called from API endpoint
            return True
        return False
