from collections import defaultdict
from datetime import datetime
import re

import pytz

from model.product_catalog_model import ProductCatalogModel
from model.user_model import UserModel
from utils.design_helper import ensure_design_local
from utils.ai_visual_helper import index_design_file

from MongoDBConnection import db

orders_collection = db["orders"]
products_collection = db["products"]
VN_TZ = pytz.timezone("Asia/Ho_Chi_Minh")


class ImportModel:
    @staticmethod
    def _parse_address(address: str):
        parts = [part.strip() for part in (address or "").split(",") if part.strip()]

        street = parts[0] if len(parts) > 0 else ""
        city = parts[1] if len(parts) > 1 else ""
        state = parts[2] if len(parts) > 2 else ""
        zip_code = parts[3] if len(parts) > 3 else ""
        country = parts[4] if len(parts) > 4 else ""

        return {
            "street": street,
            "city": city,
            "state": state,
            "country": country,
            "zipCode": zip_code,
        }

    @staticmethod
    def _normalize_compare_text(value):
        text = str(value or "")
        text = re.sub(r"\s+", " ", text).strip()
        return text.upper()

    @staticmethod
    def _normalize_variant_text(value):
        text = str(value or "")
        text = re.sub(r"\s+", " ", text).strip()
        return text.lower()

    @staticmethod
    def _get_variant_tier(variant: dict):
        return str((variant or {}).get("tier") or (variant or {}).get("material") or "").strip()

    @staticmethod
    def _resolve_user_tier_for_preview(id_khach_hang: str = None):
        if not id_khach_hang:
            return "Silver"

        try:
            if hasattr(UserModel, "get_tier_snapshot"):
                snapshot = UserModel.get_tier_snapshot(str(id_khach_hang))
                return str(snapshot.get("tierCurrent") or "Silver")
        except Exception:
            pass

        try:
            user = UserModel.get_user_by_id(str(id_khach_hang))
            if user:
                return str(user.get("tierCurrent") or "Silver")
        except Exception:
            pass

        return "Silver"

    @staticmethod
    def _build_group_key(row: dict):
        customer_name = ImportModel._normalize_compare_text(row.get("customer", ""))
        parsed_address = ImportModel._parse_address(row.get("address", ""))

        street = ImportModel._normalize_compare_text(parsed_address.get("street", ""))
        city = ImportModel._normalize_compare_text(parsed_address.get("city", ""))
        state = ImportModel._normalize_compare_text(parsed_address.get("state", ""))
        country = ImportModel._normalize_compare_text(parsed_address.get("country", ""))
        zip_code = ImportModel._normalize_compare_text(parsed_address.get("zipCode", ""))

        return "||".join([
            customer_name,
            street,
            city,
            state,
            country,
            zip_code,
        ])

    @staticmethod
    def _to_float(value, default=0):
        try:
            if value is None or value == "":
                return float(default)
            return float(str(value).replace(",", "").strip())
        except Exception:
            return float(default)

    @staticmethod
    def _to_int(value, default=1):
        try:
            if value is None or value == "":
                return int(default)
            return int(float(str(value).replace(",", "").strip()))
        except Exception:
            return int(default)

    @staticmethod
    def _build_uploader_info(id_khach_hang: str = None):
        if not id_khach_hang:
            return {
                "uploadedByName": "",
                "uploadedByEmail": "",
            }

        user = UserModel.get_user_by_id(id_khach_hang)
        if not user:
            return {
                "uploadedByName": "",
                "uploadedByEmail": "",
            }

        full_name = f"{user.get('firstName', '')} {user.get('lastName', '')}".strip()

        return {
            "uploadedByName": full_name or user.get("email", ""),
            "uploadedByEmail": user.get("email", ""),
        }

    @staticmethod
    def _get_product_display_name(product_doc: dict, row: dict, product_catalog: dict):
        product_id = str(row.get("productId") or "").strip()
        return str(
            (product_doc or {}).get("title")
            or row.get("productName")
            or product_catalog.get(product_id)
            or product_id
        ).strip()

    @staticmethod
    def _is_us_country(country_value: str):
        normalized = ImportModel._normalize_variant_text(country_value)
        us_values = {
            "us",
            "usa",
            "u.s.a",
            "united states",
            "united states of america",
            "my",
            "hoa ky",
            "nuoc my",
        }
        return normalized in us_values

    @staticmethod
    def _detect_shipping_region(row: dict):
        parsed_address = ImportModel._parse_address(row.get("address", ""))
        country = parsed_address.get("country", "")
        return "US" if ImportModel._is_us_country(country) else "International"

    @staticmethod
    def _normalize_shipping_rate(rate: dict):
        return {
            "region": str(rate.get("region") or "").strip(),
            "transitTime": str(rate.get("transitTime") or "").strip(),
            "cost": ImportModel._to_float(rate.get("cost"), 0),
            "importTax": ImportModel._to_float(rate.get("importTax"), 0),
            "importTaxNote": str(rate.get("importTaxNote") or "").strip(),
        }

    @staticmethod
    def _pick_shipping_rate(product_doc: dict, row: dict):
        shipping_rates = product_doc.get("shippingRates") or []
        if not shipping_rates:
            return {
                "region": ImportModel._detect_shipping_region(row),
                "transitTime": "",
                "cost": 0.0,
                "importTax": 0.0,
                "importTaxNote": "",
            }

        target_region = ImportModel._detect_shipping_region(row)
        normalized_target = ImportModel._normalize_variant_text(target_region)

        for rate in shipping_rates:
            normalized_rate = ImportModel._normalize_variant_text(rate.get("region"))
            if normalized_rate == normalized_target:
                return ImportModel._normalize_shipping_rate(rate)

        if target_region == "US":
            for rate in shipping_rates:
                normalized_rate = ImportModel._normalize_variant_text(rate.get("region"))
                if normalized_rate in {"us", "united states"}:
                    return ImportModel._normalize_shipping_rate(rate)
        else:
            for rate in shipping_rates:
                normalized_rate = ImportModel._normalize_variant_text(rate.get("region"))
                if normalized_rate == "international":
                    return ImportModel._normalize_shipping_rate(rate)

        return ImportModel._normalize_shipping_rate(shipping_rates[0])

    @staticmethod
    def _find_matching_variant(
        variants: list,
        requested_style: str,
        requested_size: str,
        requested_tier: str = "",
    ):
        normalized_style = ImportModel._normalize_variant_text(requested_style)
        normalized_size = ImportModel._normalize_variant_text(requested_size)
        normalized_tier = ImportModel._normalize_variant_text(requested_tier)

        exact_tier_matches = []
        fallback_matches = []

        for variant in variants:
            variant_style = ImportModel._normalize_variant_text(variant.get("style"))
            variant_size = ImportModel._normalize_variant_text(variant.get("size"))
            variant_tier = ImportModel._normalize_variant_text(ImportModel._get_variant_tier(variant))

            if variant_style == normalized_style and variant_size == normalized_size:
                fallback_matches.append(variant)

                if normalized_tier and variant_tier == normalized_tier:
                    exact_tier_matches.append(variant)

        if exact_tier_matches:
            return exact_tier_matches[0]

        if fallback_matches:
            return fallback_matches[0]

        return None

    @staticmethod
    def _build_error_detail(
        row_number: int,
        row: dict,
        reason: str,
        message: str,
        product_doc: dict = None,
        product_catalog: dict = None,
        extra: dict = None,
    ):
        product_catalog = product_catalog or {}
        extra = extra or {}

        product_name = ImportModel._get_product_display_name(product_doc, row, product_catalog)

        return {
            "row": row_number,
            "reason": reason,
            "message": message,
            "productId": str(row.get("productId") or "").strip(),
            "productName": product_name,
            "style": str(row.get("style") or "").strip(),
            "size": str(row.get("size") or "").strip(),
            "design": str(row.get("design") or "").strip(),
            "customer": str(row.get("customer") or "").strip(),
            **extra,
        }

    @staticmethod
    def _validate_basic_row(row: dict, row_number: int, product_catalog: dict):
        errors = []

        if not str(row.get("customer") or "").strip():
            errors.append(
                ImportModel._build_error_detail(
                    row_number=row_number,
                    row=row,
                    reason="MISSING_CUSTOMER",
                    message="Thiếu tên khách hàng.",
                    product_catalog=product_catalog,
                )
            )

        if not str(row.get("address") or "").strip():
            errors.append(
                ImportModel._build_error_detail(
                    row_number=row_number,
                    row=row,
                    reason="MISSING_ADDRESS",
                    message="Thiếu địa chỉ.",
                    product_catalog=product_catalog,
                )
            )

        if not str(row.get("productId") or "").strip():
            errors.append(
                ImportModel._build_error_detail(
                    row_number=row_number,
                    row=row,
                    reason="MISSING_PRODUCT_ID",
                    message="Thiếu mã sản phẩm.",
                    product_catalog=product_catalog,
                )
            )

        quantity = ImportModel._to_int(row.get("quantity"), 0)
        if quantity <= 0:
            errors.append(
                ImportModel._build_error_detail(
                    row_number=row_number,
                    row=row,
                    reason="INVALID_QUANTITY",
                    message="Số lượng phải lớn hơn 0.",
                    product_catalog=product_catalog,
                    extra={"quantity": row.get("quantity")},
                )
            )

        return errors

    @staticmethod
    def _validate_and_enrich_row(row: dict, row_number: int, product_catalog: dict, id_khach_hang: str = None):
        product_id = str(row.get("productId") or "").strip()
        product_doc = products_collection.find_one({"productId": product_id})

        product_name = ImportModel._get_product_display_name(product_doc, row, product_catalog)

        if not product_doc:
            return None, ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="PRODUCT_NOT_FOUND",
                message=f'Không tìm thấy sản phẩm "{product_name}".',
                product_doc=product_doc,
                product_catalog=product_catalog,
            )

        requested_style = str(row.get("style") or "").strip()
        requested_size = str(row.get("size") or "").strip()

        if not requested_style:
            return None, ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="MISSING_STYLE",
                message=f'Sản phẩm "{product_name}" đang thiếu style.',
                product_doc=product_doc,
                product_catalog=product_catalog,
            )

        if not requested_size:
            return None, ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="MISSING_SIZE",
                message=f'Sản phẩm "{product_name}" đang thiếu size.',
                product_doc=product_doc,
                product_catalog=product_catalog,
            )

        variants = product_doc.get("variants") or []
        if not variants:
            return None, ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="NO_VARIANTS",
                message=f'Sản phẩm "{product_name}" hiện tại không còn mặt hàng này.',
                product_doc=product_doc,
                product_catalog=product_catalog,
            )

        available_styles = {
            ImportModel._normalize_variant_text(v.get("style"))
            for v in variants
            if str(v.get("style") or "").strip()
        }

        available_sizes = {
            ImportModel._normalize_variant_text(v.get("size"))
            for v in variants
            if str(v.get("size") or "").strip()
        }

        normalized_requested_style = ImportModel._normalize_variant_text(requested_style)
        normalized_requested_size = ImportModel._normalize_variant_text(requested_size)

        if normalized_requested_style not in available_styles:
            return None, ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="STYLE_NOT_FOUND",
                message=f'Sản phẩm "{product_name}" hiện tại đã hết hoặc không có style "{requested_style}".',
                product_doc=product_doc,
                product_catalog=product_catalog,
                extra={
                    "availableStyles": sorted(
                        list({
                            str(v.get("style") or "").strip()
                            for v in variants
                            if str(v.get("style") or "").strip()
                        })
                    )
                }
            )

        if normalized_requested_size not in available_sizes:
            return None, ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="SIZE_NOT_FOUND",
                message=f'Sản phẩm "{product_name}" hiện tại đã hết hoặc không có size "{requested_size}".',
                product_doc=product_doc,
                product_catalog=product_catalog,
                extra={
                    "availableSizes": sorted(
                        list({
                            str(v.get("size") or "").strip()
                            for v in variants
                            if str(v.get("size") or "").strip()
                        })
                    )
                }
            )

        user_tier = ImportModel._resolve_user_tier_for_preview(id_khach_hang)

        matched_variant = ImportModel._find_matching_variant(
            variants=variants,
            requested_style=requested_style,
            requested_size=requested_size,
            requested_tier=user_tier,
        )

        if not matched_variant:
            return None, ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="VARIANT_NOT_FOUND",
                message=(
                    f'Sản phẩm "{product_name}" không có biến thể '
                    f'style "{requested_style}" - size "{requested_size}".'
                ),
                product_doc=product_doc,
                product_catalog=product_catalog,
            )

        shipping_rate = ImportModel._pick_shipping_rate(product_doc, row)
        quantity = ImportModel._to_int(row.get("quantity"), 1)
        variant_price = ImportModel._to_float(
            matched_variant.get("price"),
            product_doc.get("price") or 0
        )

        import_tax_per_item = ImportModel._to_float(shipping_rate.get("importTax"), 0)
        line_tax_total = quantity * import_tax_per_item
        shipping_cost_once = ImportModel._to_float(shipping_rate.get("cost"), 0)

        enriched_row = {
            **row,
            "productId": product_id,
            "productName": product_name,
            "style": requested_style,
            "size": requested_size,
            "quantity": quantity,
            "price": variant_price,   # preview price
            "previewTier": user_tier,
            "tax": line_tax_total,
            "_shipping_cost_once": shipping_cost_once,
            "_shipping_region": shipping_rate.get("region", ""),
            "_shipping_tax_note": shipping_rate.get("importTaxNote", ""),
        }

        return enriched_row, None

    @staticmethod
    def _validate_and_enrich_fba_fbt_row(row: dict, row_number: int, product_catalog: dict):
        """FBA is an internal production request and has no catalog lookup."""
        product_name = str(row.get("productName") or "").strip()
        quantity = ImportModel._to_int(row.get("quantity"), 0)
        errors = []

        if not product_name:
            errors.append(ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="MISSING_PRODUCT_NAME",
                message="Thiếu tên sản phẩm FBA.",
                product_catalog=product_catalog,
            ))
        if quantity <= 0:
            errors.append(ImportModel._build_error_detail(
                row_number=row_number,
                row=row,
                reason="INVALID_QUANTITY",
                message="Số lượng phải lớn hơn 0.",
                product_catalog=product_catalog,
            ))
        if errors:
            return None, errors

        return {
            **row,
            "productId": str(row.get("productId") or "").strip(),
            "productName": product_name,
            "customer": "FBA",
            "address": "",
            "quantity": quantity,
            "price": 0,
            "shipping": 0,
            "tax": 0,
            "status": "Liên Hệ",
        }, []

    @staticmethod
    def _attach_design_asset(row: dict, row_number: int, product_catalog: dict):
        design_value = str(row.get("design") or "").strip()

        result = ensure_design_local(
            design_value,
            filename_prefix=f"import_r{row_number}"
        )

        if result["success"]:
            row["designOriginal"] = design_value
            row["designDrive"] = design_value
            row["designLocal"] = result["publicUrl"]
            row["design"] = design_value

            # Cho AI học ảnh import vừa được lưu trong /pod-api/design
            index_design_file(result["publicUrl"])

            return row, None

        return row, ImportModel._build_error_detail(
            row_number=row_number,
            row=row,
            reason=result["reason"],
            message=result["message"],
            product_catalog=product_catalog,
            extra={"design": design_value},
        )

    @staticmethod
    def _parse_item(row: dict, product_catalog: dict, shipping_override: float = 0.0):
        item_text = (row.get("items") or "").strip()

        qty_match = re.search(r"\(Qty:\s*(\d+)\)", item_text, re.IGNORECASE)
        parsed_qty = int(qty_match.group(1)) if qty_match else 1

        product_id = str(row.get("productId") or "").strip()
        product_name = str(
            row.get("productName") or product_catalog.get(product_id) or ""
        ).strip()

        return {
            "style": str(row.get("style") or "").strip(),
            "productId": product_id,
            "productName": product_name,
            "quantity": ImportModel._to_int(row.get("quantity"), parsed_qty),
            "price": ImportModel._to_float(row.get("price"), 0),  # preview
            "size": str(row.get("size") or "").strip(),
            "design": row.get("design") or "",
            "designOriginal": row.get("designOriginal") or row.get("designDrive") or row.get("design") or "",
            "designDrive": row.get("designDrive") or row.get("designOriginal") or row.get("design") or "",
            "designLocal": row.get("designLocal") or "",
            "shipping": ImportModel._to_float(shipping_override, 0),
            "tax": ImportModel._to_float(row.get("tax"), 0),
        }

    @staticmethod
    def _get_order_shipping_once(grouped_rows: list):
        shipping_candidates = []

        for row in grouped_rows:
            if row.get("_shipping_cost_once") not in [None, ""]:
                shipping_candidates.append(
                    ImportModel._to_float(row.get("_shipping_cost_once"), 0)
                )
                continue

            shipping_candidates.append(ImportModel._to_float(row.get("shipping"), 0))

        if not shipping_candidates:
            return 0.0
        return max(shipping_candidates)

    @staticmethod
    def _build_order_doc(
        grouped_rows: list,
        file_name: str,
        product_catalog: dict,
        id_khach_hang: str = None,
        merge_key: str = "",
        created_at: str = None,
        final_order_id: str = "",
        issue_details: list = None,
        status: str = "Unpaid",
    ):
        first_row = grouped_rows[0]
        order_shipping_once = ImportModel._get_order_shipping_once(grouped_rows)
        issue_details = issue_details or []

        items = []
        for index, row in enumerate(grouped_rows):
            shipping_override = order_shipping_once if index == 0 else 0.0
            items.append(
                ImportModel._parse_item(
                    row=row,
                    product_catalog=product_catalog,
                    shipping_override=shipping_override,
                )
            )

        subtotal = sum(item["quantity"] * item["price"] for item in items)
        total_tax = sum(item["tax"] for item in items)
        total = subtotal + total_tax + order_shipping_once

        uploader_info = ImportModel._build_uploader_info(id_khach_hang)
        issue_state = ImportModel._build_issue_state(issue_details)

        return {
            "orderId": final_order_id,
            "sourceOrderIds": [],
            "mergeKey": merge_key,
            "customer": {
                "name": first_row.get("customer", ""),
                "phone": first_row.get("phone", ""),
                "email": first_row.get("email", ""),
                "address": ImportModel._parse_address(first_row.get("address", "")),
            },
            "items": items,
            "status": status,
            "total": round(total, 2),
            "id_khach_hang": id_khach_hang,
            "uploadedById": str(id_khach_hang or ""),
            "uploadedByName": uploader_info["uploadedByName"],
            "uploadedByEmail": uploader_info["uploadedByEmail"],
            "createdAt": created_at or datetime.utcnow().isoformat(),
            "importSource": file_name,
            "tracking": "",
            "trackingNumber": "",
            "trackingLink": "",
            **issue_state,
        }

    @staticmethod
    def _strip_import_meta(row: dict):
        return {
            key: value
            for key, value in (row or {}).items()
            if key not in {"_row_number", "_merge_key"}
        }

    @staticmethod
    def _build_issue_state(issue_details: list = None):
        issue_details = issue_details or []
        blocked = len(issue_details) > 0

        return {
            "paymentBlocked": blocked,
            "issueType": "IMPORT_ERROR" if blocked else "",
            "issueStatus": "needs_fix" if blocked else "",
            "issueSummary": (
                "Đơn này đang có sản phẩm hoặc ảnh thiết kế không hợp lệ. Vui lòng chỉnh sửa trước khi thanh toán."
                if blocked
                else ""
            ),
            "issueDetails": issue_details,
            "issueCount": len(issue_details),
            "issueUpdatedAt": datetime.utcnow().isoformat() if blocked else "",
        }

    @staticmethod
    def _generate_order_id(vn_now=None):
        vn_now = vn_now or datetime.now(VN_TZ)
        timestamp_part = vn_now.strftime("%Y%m%d%H%M%S")
        milli_part = f"{vn_now.microsecond // 10000:03d}"
        prefix = f"ORD-{timestamp_part}{milli_part}-"

        regex = re.compile(rf"^{re.escape(prefix)}(\d{{4}})$")

        latest_docs = orders_collection.find(
            {"orderId": {"$regex": rf"^{re.escape(prefix)}\d{{4}}$"}},
            {"orderId": 1}
        )

        max_seq = 0
        for doc in latest_docs:
            order_id = str(doc.get("orderId") or "")
            match = regex.match(order_id)
            if match:
                max_seq = max(max_seq, int(match.group(1)))

        next_seq = max_seq + 1

        while True:
            generated = f"{prefix}{str(next_seq).zfill(4)}"
            existed = orders_collection.find_one({"orderId": generated}, {"_id": 1})
            if not existed:
                return generated
            next_seq += 1

    @staticmethod
    def process_import(file_name: str, file_size: int, rows: list, id_khach_hang: str = None):
        product_catalog = ProductCatalogModel.get_product_catalog_map()

        grouped_input_rows = defaultdict(list)
        for idx, row in enumerate(rows):
            row_number = idx + 1
            merge_key = ImportModel._build_group_key(row)

            grouped_input_rows[merge_key].append({
                **row,
                "_row_number": row_number,
                "_merge_key": merge_key,
            })

        import_errors = []
        inserted_orders = []
        preview_data = []
        valid_rows_count = 0
        blocked_group_count = 0

        for merge_key, grouped_rows in grouped_input_rows.items():
            group_errors = []
            group_order_rows = []
            group_success_rows = 0

            for raw_row in grouped_rows:
                row_number = raw_row.get("_row_number", 0)
                row = ImportModel._strip_import_meta(raw_row)

                basic_errors = ImportModel._validate_basic_row(
                    row=row,
                    row_number=row_number,
                    product_catalog=product_catalog,
                )

                if basic_errors:
                    group_order_rows.append({**row, "mergeKey": merge_key})
                    group_errors.extend([
                        {**error, "mergeKey": merge_key}
                        for error in basic_errors
                    ])
                    continue

                normalized_row, variant_error = ImportModel._validate_and_enrich_row(
                    row=row,
                    row_number=row_number,
                    product_catalog=product_catalog,
                    id_khach_hang=id_khach_hang,
                )

                if variant_error:
                    group_order_rows.append({**row, "mergeKey": merge_key})
                    group_errors.append({
                        **variant_error,
                        "mergeKey": merge_key,
                    })
                    continue

                normalized_row, design_error = ImportModel._attach_design_asset(
                    row=normalized_row,
                    row_number=row_number,
                    product_catalog=product_catalog,
                )

                normalized_row["mergeKey"] = merge_key
                group_order_rows.append(normalized_row)

                if design_error:
                    group_errors.append({
                        **design_error,
                        "mergeKey": merge_key,
                    })
                    continue

                group_success_rows += 1

            issue_details = group_errors if group_errors else []
            order_rows = group_order_rows

            if issue_details:
                blocked_group_count += 1
                import_errors.extend(issue_details)

            valid_rows_count += group_success_rows

            final_order_id = ImportModel._generate_order_id()
            order_doc = ImportModel._build_order_doc(
                grouped_rows=order_rows,
                file_name=file_name,
                product_catalog=product_catalog,
                id_khach_hang=id_khach_hang,
                merge_key=merge_key,
                created_at=None,
                final_order_id=final_order_id,
                issue_details=issue_details,
            )

            orders_collection.insert_one(order_doc)
            inserted_orders.append(order_doc)

        for doc in inserted_orders[:10]:
            preview_data.append({
                "orderId": doc["orderId"],
                "sourceOrderIds": doc.get("sourceOrderIds", []),
                "customer": (doc.get("customer") or {}).get("name", ""),
                "items": f"{len(doc.get('items', []))} item(s)",
                "address": ((doc.get("customer") or {}).get("address") or {}).get("street", ""),
                "paymentBlocked": bool(doc.get("paymentBlocked")),
                "issueSummary": doc.get("issueSummary", ""),
            })

        return {
            "importId": f"IMP-{datetime.now().strftime('%Y%m%d%H%M%S')}",
            "totalRows": len(rows),
            "validRows": valid_rows_count,
            "invalidRows": len(import_errors),
            "groupedOrderCount": len(grouped_input_rows),
            "insertedOrderCount": len(inserted_orders),
            "blockedGroupedOrderCount": blocked_group_count,
            "blockedOrderCount": blocked_group_count,
            "skippedGroupedOrderCount": 0,
            "errors": import_errors,
            "previewData": preview_data,
        }

    @staticmethod
    def process_fba_fbt_import(file_name: str, file_size: int, rows: list, id_khach_hang: str = None):
        """Create one FBA order from one uploaded spreadsheet.

        Each row is a production item. FBA deliberately does not use the
        product catalog because the shipping application has no catalog to
        match against.
        """
        product_catalog = ProductCatalogModel.get_product_catalog_map()
        import_errors = []
        valid_rows = []

        for row_number, row in enumerate(rows, start=1):
            normalized_row, row_errors = ImportModel._validate_and_enrich_fba_fbt_row(
                row=row,
                row_number=row_number,
                product_catalog=product_catalog,
            )
            if row_errors:
                import_errors.extend(row_errors)
                continue
            valid_rows.append(normalized_row)

        inserted_orders = []
        if valid_rows:
            final_order_id = ImportModel._generate_order_id()
            order_doc = ImportModel._build_order_doc(
                grouped_rows=valid_rows,
                file_name=file_name,
                product_catalog=product_catalog,
                id_khach_hang=id_khach_hang,
                merge_key=f"FBA-FILE-{final_order_id}",
                final_order_id=final_order_id,
                issue_details=[],
                status="Liên Hệ",
            )

            fba_requests = []
            for index, row in enumerate(valid_rows):
                fba_request = {
                    "orderDate": str(row.get("orderDate") or "").strip(),
                    "sku": str(row.get("productId") or "").strip(),
                    "productName": str(row.get("productName") or "").strip(),
                    "size": str(row.get("size") or "").strip(),
                    "set": ImportModel._to_int(row.get("setCount"), 0),
                    "pack": ImportModel._to_int(row.get("pack"), 0),
                    "quantity": ImportModel._to_int(row.get("quantity"), 0),
                    "designLink": str(row.get("design") or "").strip(),
                    "fnskuCode": str(row.get("fnskuCode") or "").strip(),
                    "fnskuLink": str(row.get("fnskuLink") or "").strip(),
                    "note": str(row.get("note") or "").strip(),
                    "packingNote": str(row.get("packingNote") or "").strip(),
                }
                fba_requests.append(fba_request)
                if index < len(order_doc.get("items", [])):
                    order_doc["items"][index]["fbaRequest"] = fba_request

            order_doc["importType"] = "FBA&FBT"
            order_doc["fbaRequest"] = fba_requests[0]
            order_doc["fbaRequests"] = fba_requests
            order_doc["customer"]["name"] = order_doc.get("uploadedByName") or order_doc.get("uploadedByEmail") or "FBA"
            orders_collection.insert_one(order_doc)
            inserted_orders.append(order_doc)

        preview_data = [
            {
                "orderId": doc["orderId"],
                "sourceOrderIds": doc.get("sourceOrderIds", []),
                "customer": doc.get("uploadedByName") or "FBA",
                "items": f"{len(doc.get('items', []))} item(s)",
                "address": "",
                "paymentBlocked": False,
                "issueSummary": "",
            }
            for doc in inserted_orders
        ]

        return {
            "importId": f"IMP-FBA-{datetime.now().strftime('%Y%m%d%H%M%S')}",
            "totalRows": len(rows),
            "validRows": len(valid_rows),
            "invalidRows": len(import_errors),
            "groupedOrderCount": 1 if valid_rows else 0,
            "insertedOrderCount": len(inserted_orders),
            "blockedGroupedOrderCount": 0,
            "blockedOrderCount": 0,
            "skippedGroupedOrderCount": len(import_errors),
            "skippedRows": len(import_errors),
            "errors": import_errors,
            "previewData": preview_data,
        }
