# app/services/marketplace_product_service.py
"""
MarketplaceProduct service for managing product operations and data processing.

This module provides classes and functions for:
- MarketplaceProduct CRUD operations with validation
- Advanced product filtering and search
- Inventory information integration
- CSV export functionality

Note: Title and description are now stored in MarketplaceProductTranslation table.
Use get_title(language) and get_description(language) methods on the model.
"""

import csv
import logging
from collections.abc import Generator
from datetime import UTC, datetime
from io import StringIO

from sqlalchemy import or_
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
from sqlalchemy.orm import Session, joinedload

from app.modules.inventory.schemas import (
    InventoryLocationResponse,
    InventorySummaryResponse,
)
from app.modules.marketplace.exceptions import (
    InvalidMarketplaceProductDataException,
    MarketplaceException,
    MarketplaceProductAlreadyExistsException,
    MarketplaceProductNotFoundException,
    MarketplaceProductValidationException,
)
from app.modules.marketplace.models import (
    MarketplaceProduct,
    MarketplaceProductTranslation,
)
from app.modules.marketplace.schemas import (
    MarketplaceProductCreate,
    MarketplaceProductUpdate,
)
from app.utils.data_processing import GTINProcessor, PriceProcessor

logger = logging.getLogger(__name__)


class MarketplaceProductService:
    """Service class for MarketplaceProduct operations following the application's service pattern."""

    def __init__(self):
        """Class constructor."""
        self.gtin_processor = GTINProcessor()
        self.price_processor = PriceProcessor()

    def create_product(
        self,
        db: Session,
        product_data: MarketplaceProductCreate,
        title: str | None = None,
        description: str | None = None,
        language: str = "en",
    ) -> MarketplaceProduct:
        """Create a new product with validation.

        Args:
            db: Database session
            product_data: Product data from schema
            title: Product title (stored in translations table)
            description: Product description (stored in translations table)
            language: Language code for translation (default: 'en')

        Returns:
            Created MarketplaceProduct instance
        """
        try:
            # Process and validate GTIN if provided
            if product_data.gtin:
                normalized_gtin = self.gtin_processor.normalize(product_data.gtin)
                if not normalized_gtin:
                    raise InvalidMarketplaceProductDataException(
                        "Invalid GTIN format", field="gtin"
                    )
                product_data.gtin = normalized_gtin

            # Process price if provided
            if product_data.price:
                try:
                    parsed_price, currency = self.price_processor.parse_price_currency(
                        product_data.price
                    )
                    if parsed_price:
                        product_data.price = parsed_price
                        product_data.currency = currency
                except ValueError as e:
                    # Convert ValueError to domain-specific exception
                    raise InvalidMarketplaceProductDataException(str(e), field="price")

            # Set default marketplace if not provided
            if not product_data.marketplace:
                product_data.marketplace = "Letzshop"

            # Validate required fields
            if (
                not product_data.marketplace_product_id
                or not product_data.marketplace_product_id.strip()
            ):
                raise MarketplaceProductValidationException(
                    "MarketplaceProduct ID is required", field="marketplace_product_id"
                )

            # Create the product (without title/description - those go in translations)
            product_dict = product_data.model_dump(exclude={"title", "description"})

            db_product = MarketplaceProduct(**product_dict)
            db.add(db_product)
            db.flush()  # Get the ID

            # Create translation if title is provided
            if title and title.strip():
                translation = MarketplaceProductTranslation(
                    marketplace_product_id=db_product.id,
                    language=language,
                    title=title.strip(),
                    description=description.strip() if description else None,
                )
                db.add(translation)

            db.flush()
            db.refresh(db_product)

            logger.info(f"Created product {db_product.marketplace_product_id}")
            return db_product

        except (
            InvalidMarketplaceProductDataException,
            MarketplaceProductValidationException,
        ):
            raise  # Re-raise custom exceptions
        except IntegrityError as e:
            logger.error(f"Database integrity error: {str(e)}")
            if "marketplace_product_id" in str(e).lower() or "unique" in str(e).lower():
                raise MarketplaceProductAlreadyExistsException(
                    product_data.marketplace_product_id
                )
            raise MarketplaceProductValidationException(
                "Data integrity constraint violation"
            )
        except SQLAlchemyError as e:
            logger.error(f"Error creating product: {str(e)}")
            raise MarketplaceException("Failed to create product")

    def get_product_by_id(
        self, db: Session, marketplace_product_id: str
    ) -> MarketplaceProduct | None:
        """Get a product by its ID."""
        try:
            return (
                db.query(MarketplaceProduct)
                .options(joinedload(MarketplaceProduct.translations))
                .filter(
                    MarketplaceProduct.marketplace_product_id == marketplace_product_id
                )
                .first()
            )
        except SQLAlchemyError as e:
            logger.error(f"Error getting product {marketplace_product_id}: {str(e)}")
            return None

    def get_product_by_id_or_raise(
        self, db: Session, marketplace_product_id: str
    ) -> MarketplaceProduct:
        """
        Get a product by its ID or raise exception.

        Args:
            db: Database session
            marketplace_product_id: MarketplaceProduct ID to find

        Returns:
            MarketplaceProduct object

        Raises:
            MarketplaceProductNotFoundException: If product doesn't exist
        """
        product = self.get_product_by_id(db, marketplace_product_id)
        if not product:
            raise MarketplaceProductNotFoundException(marketplace_product_id)
        return product

    def get_products_with_filters(
        self,
        db: Session,
        skip: int = 0,
        limit: int = 100,
        brand: str | None = None,
        category: str | None = None,
        availability: str | None = None,
        marketplace: str | None = None,
        store_name: str | None = None,
        search: str | None = None,
        language: str = "en",
    ) -> tuple[list[MarketplaceProduct], int]:
        """
        Get products with filtering and pagination.

        Args:
            db: Database session
            skip: Number of records to skip
            limit: Maximum records to return
            brand: Brand filter
            category: Category filter
            availability: Availability filter
            marketplace: Marketplace filter
            store_name: Store name filter
            search: Search term (searches in translations too)
            language: Language for search (default: 'en')

        Returns:
            Tuple of (products_list, total_count)
        """
        try:
            query = db.query(MarketplaceProduct).options(
                joinedload(MarketplaceProduct.translations)
            )

            # Apply filters
            if brand:
                query = query.filter(MarketplaceProduct.brand.ilike(f"%{brand}%"))
            if category:
                query = query.filter(
                    MarketplaceProduct.google_product_category.ilike(f"%{category}%")
                )
            if availability:
                query = query.filter(MarketplaceProduct.availability == availability)
            if marketplace:
                query = query.filter(
                    MarketplaceProduct.marketplace.ilike(f"%{marketplace}%")
                )
            if store_name:
                query = query.filter(
                    MarketplaceProduct.store_name.ilike(f"%{store_name}%")
                )
            if search:
                # Search in marketplace, store_name, brand, and translations
                search_term = f"%{search}%"
                # Use subquery to get distinct IDs (PostgreSQL can't compare JSON for DISTINCT)
                id_subquery = (
                    db.query(MarketplaceProduct.id)
                    .outerjoin(MarketplaceProductTranslation)
                    .filter(
                        or_(
                            MarketplaceProduct.marketplace.ilike(search_term),
                            MarketplaceProduct.store_name.ilike(search_term),
                            MarketplaceProduct.brand.ilike(search_term),
                            MarketplaceProduct.gtin.ilike(search_term),
                            MarketplaceProduct.marketplace_product_id.ilike(
                                search_term
                            ),
                            MarketplaceProductTranslation.title.ilike(search_term),
                            MarketplaceProductTranslation.description.ilike(
                                search_term
                            ),
                        )
                    )
                    .distinct()
                    .subquery()
                )
                query = query.filter(
                    MarketplaceProduct.id.in_(db.query(id_subquery.c.id))
                )

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

            return products, total

        except SQLAlchemyError as e:
            logger.error(f"Error getting products with filters: {str(e)}")
            raise MarketplaceException("Failed to retrieve products")

    def update_product(
        self,
        db: Session,
        marketplace_product_id: str,
        product_update: MarketplaceProductUpdate,
        title: str | None = None,
        description: str | None = None,
        language: str = "en",
    ) -> MarketplaceProduct:
        """Update product with validation.

        Args:
            db: Database session
            marketplace_product_id: ID of product to update
            product_update: Product update data from schema
            title: Updated title (stored in translations table)
            description: Updated description (stored in translations table)
            language: Language code for translation (default: 'en')

        Returns:
            Updated MarketplaceProduct instance
        """
        try:
            product = self.get_product_by_id_or_raise(db, marketplace_product_id)

            # Update fields (exclude title/description - handled separately via translations)
            update_data = product_update.model_dump(
                exclude_unset=True, exclude={"title", "description"}
            )

            # Validate GTIN if being updated
            if "gtin" in update_data and update_data["gtin"]:
                normalized_gtin = self.gtin_processor.normalize(update_data["gtin"])
                if not normalized_gtin:
                    raise InvalidMarketplaceProductDataException(
                        "Invalid GTIN format", field="gtin"
                    )
                update_data["gtin"] = normalized_gtin

            # Process price if being updated
            if "price" in update_data and update_data["price"]:
                try:
                    parsed_price, currency = self.price_processor.parse_price_currency(
                        update_data["price"]
                    )
                    if parsed_price:
                        update_data["price"] = parsed_price
                        update_data["currency"] = currency
                except ValueError as e:
                    # Convert ValueError to domain-specific exception
                    raise InvalidMarketplaceProductDataException(str(e), field="price")

            # Apply updates to product
            for key, value in update_data.items():
                if hasattr(product, key):
                    setattr(product, key, value)

            product.updated_at = datetime.now(UTC)

            # Update or create translation if title/description provided
            if title is not None or description is not None:
                self._update_or_create_translation(
                    db, product, title, description, language
                )

            db.flush()
            db.refresh(product)

            logger.info(f"Updated product {marketplace_product_id}")
            return product

        except (
            MarketplaceProductNotFoundException,
            InvalidMarketplaceProductDataException,
            MarketplaceProductValidationException,
        ):
            raise  # Re-raise custom exceptions
        except SQLAlchemyError as e:
            logger.error(f"Error updating product {marketplace_product_id}: {str(e)}")
            raise MarketplaceException("Failed to update product")

    def _update_or_create_translation(
        self,
        db: Session,
        product: MarketplaceProduct,
        title: str | None,
        description: str | None,
        language: str,
    ) -> None:
        """Update existing translation or create new one."""
        existing = (
            db.query(MarketplaceProductTranslation)
            .filter(
                MarketplaceProductTranslation.marketplace_product_id == product.id,
                MarketplaceProductTranslation.language == language,
            )
            .first()
        )

        if existing:
            if title is not None:
                existing.title = title.strip() if title else existing.title
            if description is not None:
                existing.description = description.strip() if description else None
            existing.updated_at = datetime.now(UTC)
        else:
            # Only create if we have a title
            if title and title.strip():
                new_translation = MarketplaceProductTranslation(
                    marketplace_product_id=product.id,
                    language=language,
                    title=title.strip(),
                    description=description.strip() if description else None,
                )
                db.add(new_translation)

    def delete_product(self, db: Session, marketplace_product_id: str) -> bool:
        """
        Delete product and associated inventory.

        Args:
            db: Database session
            marketplace_product_id: MarketplaceProduct ID to delete

        Returns:
            True if deletion successful

        Raises:
            MarketplaceProductNotFoundException: If product doesn't exist
        """
        try:
            product = self.get_product_by_id_or_raise(db, marketplace_product_id)

            # Delete associated inventory entries if GTIN exists
            if product.gtin:
                from app.modules.inventory.services.inventory_service import (
                    inventory_service,
                )

                inventory_service.delete_inventory_by_gtin(db, product.gtin)

            # Translations will be cascade deleted
            db.delete(product)
            db.flush()

            logger.info(f"Deleted product {marketplace_product_id}")
            return True

        except MarketplaceProductNotFoundException:
            raise  # Re-raise custom exceptions
        except SQLAlchemyError as e:
            logger.error(f"Error deleting product {marketplace_product_id}: {str(e)}")
            raise MarketplaceException("Failed to delete product")

    def get_inventory_info(
        self, db: Session, gtin: str
    ) -> InventorySummaryResponse | None:
        """
        Get inventory information for a product by GTIN.

        Args:
            db: Database session
            gtin: GTIN to look up inventory for

        Returns:
            InventorySummaryResponse if inventory found, None otherwise
        """
        try:
            # SVC-005 - Admin/internal function for inventory lookup by GTIN
            from app.modules.inventory.services.inventory_service import (
                inventory_service,
            )

            inventory_entries = inventory_service.get_inventory_by_gtin(db, gtin)
            if not inventory_entries:
                return None

            total_quantity = sum(entry.quantity for entry in inventory_entries)
            locations = [
                InventoryLocationResponse(
                    location=entry.bin_location,
                    quantity=entry.quantity,
                    reserved_quantity=entry.reserved_quantity or 0,
                    available_quantity=entry.quantity - (entry.reserved_quantity or 0),
                )
                for entry in inventory_entries
            ]

            return InventorySummaryResponse(
                gtin=gtin, total_quantity=total_quantity, locations=locations
            )

        except SQLAlchemyError as e:
            logger.error(f"Error getting inventory info for GTIN {gtin}: {str(e)}")
            return None

    def generate_csv_export(
        self,
        db: Session,
        marketplace: str | None = None,
        store_name: str | None = None,
        language: str = "en",
    ) -> Generator[str, None, None]:
        """
        Generate CSV export with streaming for memory efficiency and proper CSV escaping.

        Args:
            db: Database session
            marketplace: Optional marketplace filter
            store_name: Optional store name filter
            language: Language code for title/description (default: 'en')

        Yields:
            CSV content as strings with proper escaping
        """
        try:
            # Create a StringIO buffer for CSV writing
            output = StringIO()
            writer = csv.writer(output, quoting=csv.QUOTE_MINIMAL)

            # Write header row
            headers = [
                "marketplace_product_id",
                "title",
                "description",
                "link",
                "image_link",
                "availability",
                "price",
                "currency",
                "brand",
                "gtin",
                "marketplace",
                "store_name",
            ]
            writer.writerow(headers)
            yield output.getvalue()

            # Clear buffer for reuse
            output.seek(0)
            output.truncate(0)

            batch_size = 1000
            offset = 0

            while True:
                query = db.query(MarketplaceProduct).options(
                    joinedload(MarketplaceProduct.translations)
                )

                # Apply marketplace filters
                if marketplace:
                    query = query.filter(
                        MarketplaceProduct.marketplace.ilike(f"%{marketplace}%")
                    )
                if store_name:
                    query = query.filter(
                        MarketplaceProduct.store_name.ilike(f"%{store_name}%")
                    )

                products = query.offset(offset).limit(batch_size).all()
                if not products:
                    break

                for product in products:
                    # Get title and description from translations
                    title = product.get_title(language) or ""
                    description = product.get_description(language) or ""

                    # Create CSV row with proper escaping
                    row_data = [
                        product.marketplace_product_id or "",
                        title,
                        description,
                        product.link or "",
                        product.image_link or "",
                        product.availability or "",
                        product.price or "",
                        product.currency or "",
                        product.brand or "",
                        product.gtin or "",
                        product.marketplace or "",
                        product.store_name or "",
                    ]

                    writer.writerow(row_data)
                    yield output.getvalue()

                    # Clear buffer for next row
                    output.seek(0)
                    output.truncate(0)

                offset += batch_size

        except SQLAlchemyError as e:
            logger.error(f"Error generating CSV export: {str(e)}")
            raise MarketplaceException("Failed to generate CSV export")

    def product_exists(self, db: Session, marketplace_product_id: str) -> bool:
        """Check if product exists by ID."""
        try:
            return (
                db.query(MarketplaceProduct)
                .filter(
                    MarketplaceProduct.marketplace_product_id == marketplace_product_id
                )
                .first()
                is not None
            )
        except SQLAlchemyError as e:
            logger.error(f"Error checking if product exists: {str(e)}")
            return False

    # Private helper methods
    def _validate_product_data(self, product_data: dict) -> None:
        """Validate product data structure."""
        required_fields = ["marketplace_product_id"]

        for field in required_fields:
            if field not in product_data or not product_data[field]:
                raise MarketplaceProductValidationException(
                    f"{field} is required", field=field
                )

    def _normalize_product_data(self, product_data: dict) -> dict:
        """Normalize and clean product data."""
        normalized = product_data.copy()

        # Trim whitespace from string fields
        string_fields = [
            "marketplace_product_id",
            "brand",
            "marketplace",
            "store_name",
        ]
        for field in string_fields:
            if field in normalized and normalized[field]:
                normalized[field] = normalized[field].strip()

        return normalized

    # =========================================================================
    # Admin-specific methods for marketplace product management
    # =========================================================================

    def get_admin_products(
        self,
        db: Session,
        skip: int = 0,
        limit: int = 50,
        search: str | None = None,
        marketplace: str | None = None,
        store_name: str | None = None,
        availability: str | None = None,
        is_active: bool | None = None,
        is_digital: bool | None = None,
        language: str = "en",
    ) -> tuple[list[dict], int]:
        """
        Get marketplace products for admin with search and filtering.

        Returns:
            Tuple of (products list as dicts, total count)
        """
        query = db.query(MarketplaceProduct).options(
            joinedload(MarketplaceProduct.translations)
        )

        if search:
            search_term = f"%{search}%"
            # Use subquery to get distinct IDs (PostgreSQL can't compare JSON for DISTINCT)
            id_subquery = (
                db.query(MarketplaceProduct.id)
                .outerjoin(MarketplaceProductTranslation)
                .filter(
                    or_(
                        MarketplaceProductTranslation.title.ilike(search_term),
                        MarketplaceProduct.gtin.ilike(search_term),
                        MarketplaceProduct.sku.ilike(search_term),
                        MarketplaceProduct.brand.ilike(search_term),
                        MarketplaceProduct.mpn.ilike(search_term),
                        MarketplaceProduct.marketplace_product_id.ilike(search_term),
                    )
                )
                .distinct()
                .subquery()
            )
            query = query.filter(MarketplaceProduct.id.in_(db.query(id_subquery.c.id)))

        if marketplace:
            query = query.filter(MarketplaceProduct.marketplace == marketplace)

        if store_name:
            query = query.filter(MarketplaceProduct.store_name.ilike(f"%{store_name}%"))

        if availability:
            query = query.filter(MarketplaceProduct.availability == availability)

        if is_active is not None:
            query = query.filter(MarketplaceProduct.is_active == is_active)

        if is_digital is not None:
            query = query.filter(MarketplaceProduct.is_digital == is_digital)

        total = query.count()

        products = (
            query.order_by(MarketplaceProduct.updated_at.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )

        result = []
        for product in products:
            title = product.get_title(language)
            result.append(self._build_admin_product_item(product, title))

        return result, total

    def get_admin_product_stats(
        self,
        db: Session,
        marketplace: str | None = None,
        store_name: str | None = None,
    ) -> dict:
        """Get product statistics for admin dashboard.

        Args:
            db: Database session
            marketplace: Optional filter by marketplace (e.g., 'Letzshop')
            store_name: Optional filter by store name
        """
        from sqlalchemy import func

        # Build base filter
        base_filters = []
        if marketplace:
            base_filters.append(MarketplaceProduct.marketplace == marketplace)
        if store_name:
            base_filters.append(MarketplaceProduct.store_name == store_name)

        base_query = db.query(func.count(MarketplaceProduct.id))
        if base_filters:
            base_query = base_query.filter(*base_filters)

        total = base_query.scalar() or 0

        active_query = db.query(func.count(MarketplaceProduct.id)).filter(
            MarketplaceProduct.is_active == True  # noqa: E712
        )
        if base_filters:
            active_query = active_query.filter(*base_filters)
        active = active_query.scalar() or 0
        inactive = total - active

        digital_query = db.query(func.count(MarketplaceProduct.id)).filter(
            MarketplaceProduct.is_digital == True  # noqa: E712
        )
        if base_filters:
            digital_query = digital_query.filter(*base_filters)
        digital = digital_query.scalar() or 0
        physical = total - digital

        marketplace_query = db.query(
            MarketplaceProduct.marketplace,
            func.count(MarketplaceProduct.id),
        )
        if base_filters:
            marketplace_query = marketplace_query.filter(*base_filters)
        marketplace_counts = marketplace_query.group_by(
            MarketplaceProduct.marketplace
        ).all()
        by_marketplace = {mp or "unknown": count for mp, count in marketplace_counts}

        return {
            "total": total,
            "active": active,
            "inactive": inactive,
            "digital": digital,
            "physical": physical,
            "by_marketplace": by_marketplace,
        }

    def get_marketplaces_list(self, db: Session) -> list[str]:
        """Get list of unique marketplaces in the product catalog."""
        marketplaces = (
            db.query(MarketplaceProduct.marketplace)
            .distinct()
            .filter(MarketplaceProduct.marketplace.isnot(None))
            .all()
        )
        return [m[0] for m in marketplaces if m[0]]

    def get_source_stores_list(self, db: Session) -> list[str]:
        """Get list of unique store names in the product catalog."""
        stores = (
            db.query(MarketplaceProduct.store_name)
            .distinct()
            .filter(MarketplaceProduct.store_name.isnot(None))
            .all()
        )
        return [v[0] for v in stores if v[0]]

    def get_admin_product_detail(self, db: Session, product_id: int) -> dict:
        """Get detailed product information by database ID."""
        product = (
            db.query(MarketplaceProduct)
            .options(joinedload(MarketplaceProduct.translations))
            .filter(MarketplaceProduct.id == product_id)
            .first()
        )

        if not product:
            raise MarketplaceProductNotFoundException(
                f"Marketplace product with ID {product_id} not found"
            )

        translations = {}
        for t in product.translations:
            translations[t.language] = {
                "title": t.title,
                "description": t.description,
                "short_description": t.short_description,
            }

        return {
            "id": product.id,
            "marketplace_product_id": product.marketplace_product_id,
            "gtin": product.gtin,
            "mpn": product.mpn,
            "sku": product.sku,
            "brand": product.brand,
            "marketplace": product.marketplace,
            "store_name": product.store_name,
            "source_url": product.source_url,
            "price": product.price,
            "price_numeric": product.price_numeric,
            "sale_price": product.sale_price,
            "sale_price_numeric": product.sale_price_numeric,
            "currency": product.currency,
            "availability": product.availability,
            "condition": product.condition,
            "image_link": product.image_link,
            "additional_images": product.additional_images,
            "is_active": product.is_active,
            "is_digital": product.is_digital,
            "product_type_enum": product.product_type_enum,
            "platform": product.platform,
            "google_product_category": product.google_product_category,
            "category_path": product.category_path,
            "color": product.color,
            "size": product.size,
            "weight": product.weight,
            "weight_unit": product.weight_unit,
            "translations": translations,
            "created_at": product.created_at.isoformat()
            if product.created_at
            else None,
            "updated_at": product.updated_at.isoformat()
            if product.updated_at
            else None,
        }

    def copy_to_store_catalog(
        self,
        db: Session,
        marketplace_product_ids: list[int],
        store_id: int,
        skip_existing: bool = True,
    ) -> dict:
        """
        Copy marketplace products to a store's catalog.

        Creates independent store products with ALL fields copied from the
        marketplace product. Each store product is a standalone entity - no
        field inheritance or fallback logic. The marketplace_product_id FK is
        kept for "view original source" feature.

        Also copies ALL translations from the marketplace product.

        Returns:
            Dict with copied, skipped, failed counts and details
        """
        from app.modules.catalog.models import Product, ProductTranslation
        from app.modules.tenancy.services.store_service import store_service

        store = store_service.get_store_by_id_optional(db, store_id)
        if not store:
            from app.modules.tenancy.exceptions import StoreNotFoundException

            raise StoreNotFoundException(str(store_id), identifier_type="id")

        marketplace_products = (
            db.query(MarketplaceProduct)
            .options(joinedload(MarketplaceProduct.translations))
            .filter(MarketplaceProduct.id.in_(marketplace_product_ids))
            .all()
        )

        if not marketplace_products:
            raise MarketplaceProductNotFoundException("No marketplace products found")

        # Check product limit from subscription
        from sqlalchemy import func

        from app.modules.billing.services.feature_service import feature_service

        current_products = (
            db.query(func.count(Product.id))
            .filter(Product.store_id == store_id)
            .scalar()
            or 0
        )

        # Get effective products_limit via feature_service (resolves store→merchant→tier)
        merchant_id, platform_id = feature_service._get_merchant_for_store(db, store_id)
        products_limit = None
        if merchant_id and platform_id:
            products_limit = feature_service.get_effective_limit(
                db, merchant_id, platform_id, "products_limit"
            )
        remaining_capacity = (
            products_limit - current_products if products_limit is not None else None
        )

        copied = 0
        skipped = 0
        failed = 0
        limit_reached = False
        details = []

        for mp in marketplace_products:
            # Check if we've hit the product limit
            if remaining_capacity is not None and copied >= remaining_capacity:
                limit_reached = True
                details.append(
                    {
                        "id": mp.id,
                        "status": "skipped",
                        "reason": "Product limit reached",
                    }
                )
                skipped += 1
                continue
            try:
                existing = (
                    db.query(Product)
                    .filter(
                        Product.store_id == store_id,
                        Product.marketplace_product_id == mp.id,
                    )
                    .first()
                )

                if existing:
                    skipped += 1
                    details.append(
                        {
                            "id": mp.id,
                            "status": "skipped",
                            "reason": "Already exists in catalog",
                        }
                    )
                    continue

                # Create store product with ALL fields copied from marketplace
                product = Product(
                    store_id=store_id,
                    marketplace_product_id=mp.id,
                    # === Store settings (defaults) ===
                    is_active=True,
                    is_featured=False,
                    # === Product identifiers ===
                    gtin=mp.gtin,
                    gtin_type=mp.gtin_type if hasattr(mp, "gtin_type") else None,
                    # === Pricing (copy from marketplace) ===
                    price_cents=mp.price_cents,
                    sale_price_cents=mp.sale_price_cents,
                    currency=mp.currency or "EUR",
                    # === Product info ===
                    brand=mp.brand,
                    condition=mp.condition,
                    availability=mp.availability,
                    # === Media ===
                    primary_image_url=mp.image_link,
                    additional_images=mp.additional_images,
                    # === Digital product fields ===
                    download_url=mp.download_url
                    if hasattr(mp, "download_url")
                    else None,
                    license_type=mp.license_type
                    if hasattr(mp, "license_type")
                    else None,
                )

                db.add(product)  # noqa: PERF006
                db.flush()  # Get product.id for translations

                # Copy ALL translations from marketplace product
                translations_copied = 0
                for mpt in mp.translations:
                    product_translation = ProductTranslation(
                        product_id=product.id,
                        language=mpt.language,
                        title=mpt.title,
                        description=mpt.description,
                        short_description=mpt.short_description,
                        meta_title=mpt.meta_title,
                        meta_description=mpt.meta_description,
                        url_slug=mpt.url_slug,
                    )
                    db.add(product_translation)  # noqa: PERF006
                    translations_copied += 1

                copied += 1
                details.append(
                    {
                        "id": mp.id,
                        "status": "copied",
                        "gtin": mp.gtin,
                        "translations_copied": translations_copied,
                    }
                )

            except SQLAlchemyError as e:
                logger.error(f"Failed to copy product {mp.id}: {str(e)}")
                failed += 1
                details.append({"id": mp.id, "status": "failed", "reason": str(e)})

        db.flush()

        # Auto-match pending order item exceptions
        # Collect GTINs and their product IDs from newly copied products
        from app.modules.orders.services.order_item_exception_service import (
            order_item_exception_service,
        )

        gtin_to_product: dict[str, int] = {}
        for detail in details:
            if detail.get("status") == "copied" and detail.get("gtin"):
                # Find the product we just created
                product = (
                    db.query(Product)
                    .filter(
                        Product.store_id == store_id,
                        Product.gtin == detail["gtin"],
                    )
                    .first()
                )
                if product:
                    gtin_to_product[detail["gtin"]] = product.id

        auto_matched = 0
        if gtin_to_product:
            auto_matched = order_item_exception_service.auto_match_batch(
                db, store_id, gtin_to_product
            )
            if auto_matched:
                logger.info(
                    f"Auto-matched {auto_matched} order item exceptions "
                    f"during product copy to store {store_id}"
                )

        logger.info(
            f"Copied {copied} products to store {store.name} "
            f"(skipped: {skipped}, failed: {failed}, auto_matched: {auto_matched})"
        )

        return {
            "copied": copied,
            "skipped": skipped,
            "failed": failed,
            "auto_matched": auto_matched,
            "limit_reached": limit_reached,
            "details": details if len(details) <= 100 else None,
        }

    def _build_admin_product_item(
        self, product: MarketplaceProduct, title: str | None
    ) -> dict:
        """Build a product list item dict for admin view."""
        return {
            "id": product.id,
            "marketplace_product_id": product.marketplace_product_id,
            "title": title,
            "brand": product.brand,
            "gtin": product.gtin,
            "sku": product.sku,
            "marketplace": product.marketplace,
            "store_name": product.store_name,
            "price_numeric": product.price_numeric,
            "currency": product.currency,
            "availability": product.availability,
            "image_link": product.image_link,
            "is_active": product.is_active,
            "is_digital": product.is_digital,
            "product_type_enum": product.product_type_enum,
            "created_at": product.created_at.isoformat()
            if product.created_at
            else None,
            "updated_at": product.updated_at.isoformat()
            if product.updated_at
            else None,
        }


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

    def get_staging_product_count(self, db: Session, store_name: str) -> int:
        """
        Count staging products by store name.

        Args:
            db: Database session
            store_name: Store name (marketplace uses store_name, not store_id)

        Returns:
            Product count
        """
        from sqlalchemy import func

        return (
            db.query(func.count(MarketplaceProduct.id))
            .filter(MarketplaceProduct.store_name == store_name)
            .scalar()
            or 0
        )

    def get_distinct_brand_count(self, db: Session) -> int:
        """
        Count distinct brands across all marketplace products.

        Args:
            db: Database session

        Returns:
            Number of distinct brands
        """
        from sqlalchemy import func

        return (
            db.query(func.count(func.distinct(MarketplaceProduct.brand)))
            .filter(MarketplaceProduct.brand.isnot(None))
            .scalar()
            or 0
        )

    def get_distinct_category_count(self, db: Session) -> int:
        """
        Count distinct Google product categories.

        Args:
            db: Database session

        Returns:
            Number of distinct categories
        """
        from sqlalchemy import func

        return (
            db.query(
                func.count(func.distinct(MarketplaceProduct.google_product_category))
            )
            .filter(MarketplaceProduct.google_product_category.isnot(None))
            .scalar()
            or 0
        )


    def get_marketplace_breakdown(self, db: Session) -> list[dict]:
        """
        Get product statistics broken down by marketplace source.

        Returns:
            List of dicts with marketplace, total_products, unique_stores, unique_brands
        """
        from sqlalchemy import func

        stats = (
            db.query(
                MarketplaceProduct.marketplace,
                func.count(MarketplaceProduct.id).label("total_products"),
                func.count(func.distinct(MarketplaceProduct.store_name)).label("unique_stores"),
                func.count(func.distinct(MarketplaceProduct.brand)).label("unique_brands"),
            )
            .filter(MarketplaceProduct.marketplace.isnot(None))
            .group_by(MarketplaceProduct.marketplace)
            .all()
        )
        return [
            {
                "marketplace": s.marketplace,
                "total_products": s.total_products,
                "unique_stores": s.unique_stores,
                "unique_brands": s.unique_brands,
            }
            for s in stats
        ]

    def get_distinct_marketplace_count(self, db: Session) -> int:
        """
        Count distinct marketplace sources.

        Args:
            db: Database session

        Returns:
            Number of distinct marketplaces
        """
        from sqlalchemy import func

        return (
            db.query(func.count(func.distinct(MarketplaceProduct.marketplace)))
            .filter(MarketplaceProduct.marketplace.isnot(None))
            .scalar()
            or 0
        )


# Create service instance
marketplace_product_service = MarketplaceProductService()
