from __future__ import annotations

import hashlib
import math
import re
import secrets
import tkinter as tk
import json
from copy import copy, deepcopy
from datetime import datetime
from pathlib import Path
from tkinter import filedialog, messagebox, ttk
from urllib.parse import quote, urlparse, urlsplit, urlunsplit
from urllib.request import Request

from openpyxl import Workbook, load_workbook
from openpyxl.utils import get_column_letter
from PIL import ImageTk

from app_core.paths import DATA_DIR, DB_PATH, DEBUG_DIR, PROJECT_DIR
from app_core.filter_helpers import create_extra_filter_row, destroy_filter_row, regrid_filter_rows
from app_core.http_client import open_url
from app_core.server_api import fetch_app_setting, save_app_setting
from app_core.ui_helpers import configure_striped_treeview, create_contained_photo
from database import get_app_setting, list_order_records, normalize_style_identifier, set_app_setting


PRODUCTION_APP_SETTING_KEY = "production_order_records"
PRODUCTION_FACTORY_APP_SETTING_KEY = "production_factory_records"
PRODUCTION_PACKING_LIST_ASSETS_KEY = "production_packing_list_assets"
PRODUCTION_CARTON_STICKER_ASSETS_KEY = "production_carton_sticker_assets"
PRODUCTION_TREE_THUMBNAIL_LIMIT = 80
PRODUCTION_TREE_RENDER_LIMIT = 500
_PRODUCTION_DEBUG_LOG_PATH = DEBUG_DIR / "production_debug.log"
try:
    if _PRODUCTION_DEBUG_LOG_PATH.exists():
        _PRODUCTION_DEBUG_LOG_PATH.unlink()
except Exception:
    pass


def _append_production_debug_log(message: str) -> None:
    try:
        DEBUG_DIR.mkdir(parents=True, exist_ok=True)
        with _PRODUCTION_DEBUG_LOG_PATH.open("a", encoding="utf-8") as handle:
            handle.write(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {message}\n")
    except Exception:
        pass

PRODUCTION_COLUMNS = (
    "select_flag",
    "created_at",
    "production_order",
    "factory",
    "mr_pic",
    "buyer",
    "style",
    "parent",
    "season",
    "po_number",
    "po_date",
    "po_time",
    "ship_date",
    "cancel_date",
    "ex_fty_date_plan",
    "actual_ex_fty",
    "color",
    "size_range",
    "size_scale",
    "order_qty",
    "ship_qty",
    "status",
    "over_short_ship_qty",
    "over_short_ship_percent",
    "final_inspection_date",
    "carton_qty",
    "odd_carton_qty",
    "cbm",
    "net_weight",
    "gross_weight",
    "updated_at",
    "latest_user",
)

PRODUCTION_FIELD_LABELS = {
    "select_flag": "Export",
    "created_at": "Create Time",
    "production_order": "Production Order",
    "factory": "Factory",
    "mr_pic": "MR P.I.C",
    "buyer": "Buyer",
    "style": "Style",
    "parent": "Parent",
    "season": "Season",
    "po_number": "PO Number",
    "dept_number": "Dept Number",
    "store_number": "Store",
    "po_date": "PO date",
    "po_time": "PO time",
    "ship_date": "Ship date",
    "cancel_date": "Cancel date",
    "ex_fty_date_plan": "Ex-fty date Plan",
    "actual_ex_fty": "ACTUAL EX-FTY",
    "color": "Color",
    "size_range": "Size Range",
    "size_scale": "Size Scale",
    "order_qty": "Order Qty",
    "ship_qty": "Ship Qty",
    "status": "Status",
    "over_short_ship_qty": "Over/Short ship qty",
    "over_short_ship_percent": "Over/Short ship %",
    "final_inspection_date": "Final inspection date",
    "fabric_weight": "Fabric weight",
    "fabric_weight_uom": "Fabric Weight UOM",
    "actual_cut_qty": "Actual Cut Qty",
    "carton_qty": "Carton Qty",
    "odd_carton_qty": "ODD CARTON QTY",
    "unit_per_carton": "Unit per carton",
    "carton_dimension": "Carton dimension",
    "odd_carton_dimension": "ODD carton dimension",
    "cbm": "CBM",
    "net_weight": "Net weight",
    "gross_weight": "Gross weight",
    "updated_at": "Revised time",
    "latest_user": "Latest User",
}

PRODUCTION_FIELD_LABEL_KEYS = {
    "select_flag": "tree_export",
    "created_at": "create_time_column",
    "production_order": "production_order_column",
    "factory": "production_factory_column",
    "mr_pic": "production_mr_pic_column",
    "buyer": "production_buyer_column",
    "style": "samples_style_column",
    "parent": "production_parent_column",
    "season": "production_season_column",
    "po_number": "production_po_number_column",
    "dept_number": "production_dept_number_column",
    "store_number": "production_store_column",
    "po_date": "production_po_date_column",
    "po_time": "production_po_time_column",
    "ship_date": "production_ship_date_column",
    "cancel_date": "production_cancel_date_column",
    "ex_fty_date_plan": "production_ex_fty_date_plan_column",
    "actual_ex_fty": "production_actual_ex_fty_column",
    "color": "samples_color_column",
    "size_range": "production_size_range_column",
    "size_scale": "production_size_scale_column",
    "order_qty": "production_order_qty_column",
    "ship_qty": "production_ship_qty_column",
    "status": "status",
    "over_short_ship_qty": "production_over_short_ship_qty_column",
    "over_short_ship_percent": "production_over_short_ship_percent_column",
    "final_inspection_date": "production_final_inspection_date_column",
    "carton_qty": "production_carton_qty_column",
    "odd_carton_qty": "production_odd_carton_qty_column",
    "unit_per_carton": "production_unit_per_carton_column",
    "carton_dimension": "production_carton_dimension_column",
    "odd_carton_dimension": "production_odd_carton_dimension_column",
    "cbm": "production_cbm_column",
    "net_weight": "production_net_weight_column",
    "gross_weight": "production_gross_weight_column",
    "updated_at": "revised_time_column",
    "latest_user": "latest_user_column",
}

PRODUCTION_SORT_KEY_OPTIONS = [
    ("created_at", "Create Time"),
    ("production_order", "Production Order"),
    ("factory", "Factory"),
    ("mr_pic", "MR P.I.C"),
    ("buyer", "Buyer"),
    ("style", "Style"),
    ("parent", "Parent"),
    ("season", "Season"),
    ("po_number", "PO Number"),
    ("po_date", "PO date"),
    ("ship_date", "Ship date"),
    ("cancel_date", "Cancel date"),
    ("ex_fty_date_plan", "Ex-fty date Plan"),
    ("actual_ex_fty", "ACTUAL EX-FTY"),
    ("color", "Color"),
    ("order_qty", "Order Qty"),
    ("ship_qty", "Ship Qty"),
    ("status", "Status"),
    ("final_inspection_date", "Final inspection date"),
    ("updated_at", "Revised time"),
]

PRODUCTION_FILTER_FIELD_OPTIONS = [("__all__", "All")] + [
    ("image_path", "Image"),
    *[
    (key, PRODUCTION_FIELD_LABELS[key])
    for key in PRODUCTION_COLUMNS
    if key != "select_flag"
    ],
]

PRODUCTION_DATE_FILTER_FIELDS = {
    "created_at",
    "po_date",
    "ship_date",
    "cancel_date",
    "ex_fty_date_plan",
    "actual_ex_fty",
    "final_inspection_date",
    "updated_at",
}


def production_field_label(self, key: str) -> str:
    text_key = PRODUCTION_FIELD_LABEL_KEYS.get(key)
    if text_key:
        return self.t(text_key)
    return PRODUCTION_FIELD_LABELS.get(key, key)


def production_filter_label(self, key: str) -> str:
    if key == "__all__":
        return self.t("samples_filter_all_option")
    if key == "image_path":
        return self.t("production_image_column")
    return self.production_field_label(key)


def production_sort_label(self, key: str) -> str:
    return self.production_field_label(key)

PRODUCTION_NUMERIC_SORT_FIELDS = {
    "order_qty",
    "ship_qty",
    "over_short_ship_qty",
    "over_short_ship_percent",
    "carton_qty",
    "odd_carton_qty",
    "cbm",
    "net_weight",
    "gross_weight",
}

PRODUCTION_STATUS_OPTIONS = ["draft", "checking", "approved", "shipped", "closed"]
PRODUCTION_CARTON_DIMENSION_OPTIONS = [
    "60 x 48 x 25 (cm)",
    "60 x 48 x 15 (cm)",
]
PRODUCTION_PACKING_LIST_TEMPLATE_PATH = PROJECT_DIR / "assets" / "templates" / "packing_list_form.xlsx"
PRODUCTION_PACKING_LIST_TEMPLATE_FALLBACK_PATH = r"C:\Users\ADMIN\Desktop\Packing list form.xlsx"
PRODUCTION_PACKING_LIST_TEMPLATE_URL = "https://texmind.xyz/shared/packing-list-assets/packing_list_form.xlsx"
PRODUCTION_CARTON_STICKER_TEMPLATE_PATH = PROJECT_DIR / "assets" / "templates" / "Bealls_Carton_Label_Sticker_TAG.xlsx"
PRODUCTION_CARTON_STICKER_TEMPLATE_FALLBACK_PATH = r"C:\Users\ADMIN\Desktop\Bealls_Carton_Label_Sticker_TAG.xlsx"
PRODUCTION_CARTON_STICKER_TEMPLATE_URL = "https://texmind.xyz/shared/carton-sticker-assets/20260727/e572a1c5a646458e8cc18129f6a5f7ed/Bealls_Carton_Label_Sticker_TAG.xlsx"
PRODUCTION_LIQUIDATION_TEMPLATE_PATH = PROJECT_DIR / "assets" / "templates" / "Liquidation template.xlsx"
PRODUCTION_LIQUIDATION_TEMPLATE_FALLBACK_PATH = r"C:\Users\ADMIN\Desktop\Liquidation template.xlsx"
PRODUCTION_FABRIC_WEIGHT_UOM_OPTIONS = ("KG", "LBS")
PRODUCTION_SAVED_DETAIL_KEYS = (
    "record_id",
    "source_type",
    "source_order_id",
    "source_item_key",
    "production_order",
    "style",
    "season",
    "po_number",
    "factory",
    "mr_pic",
    "ex_fty_date_plan",
    "actual_ex_fty",
    "ship_qty",
    "status",
    "final_inspection_date",
    "actual_cut_qty",
    "carton_qty",
    "odd_carton_qty",
    "unit_per_carton",
    "carton_dimension",
    "odd_carton_dimension",
    "cbm",
    "net_weight",
    "gross_weight",
    "updated_at",
    "latest_user",
    "notes",
    "materials_json",
)
PRODUCTION_STYLE_SEASON_SHARED_KEYS = {
    "factory",
    "mr_pic",
    "unit_per_carton",
}
PRODUCTION_FACTORY_STATUS_OPTIONS = ["Active", "Inactive", "Draft", "Blocked"]
PRODUCTION_FACTORY_COLUMNS = (
    "factory_code",
    "factory_name",
    "contact_person",
    "phone",
    "email",
    "country",
    "status",
    "updated_at",
)
PRODUCTION_PO_LINE_ITEM_COLUMNS = (
    "sku",
    "mfg_style",
    "mfg_color",
    "size_desc",
    "description",
    "upc",
    "cost_unit",
    "comp",
    "retail",
    "pack_qty",
    "total_packs",
    "total_units",
)
PRODUCTION_MATERIAL_COLUMNS = (
    "costing_id",
    "item_code",
    "item_name",
    "type",
    "section",
    "color",
    "consumption",
    "uom",
    "waste_percent",
    "required_qty",
    "fabric_weight",
    "note",
)
PRODUCTION_MATERIAL_STORAGE_KEYS = ("line_id",) + PRODUCTION_MATERIAL_COLUMNS
PRODUCTION_FACTORY_DEMO_ROWS = [
    {
        "factory_code": "SUN-VN01",
        "factory_name": "Sunny Apparel Vietnam",
        "short_name": "Sunny VN",
        "contact_person": "Ms. Lan",
        "phone": "+84 28 5555 0101",
        "email": "factory.vn@sunny.example",
        "country": "Vietnam",
        "city": "Ho Chi Minh",
        "address_line": "Lot A1, Garment Industrial Park",
        "capacity_month": "120000",
        "status": "Active",
        "note": "Demo factory for woven and knit production.",
    },
    {
        "factory_code": "SUN-CN02",
        "factory_name": "Sunny Garment Shenzhen",
        "short_name": "Sunny SZ",
        "contact_person": "Mr. Chen",
        "phone": "+86 755 5555 0202",
        "email": "factory.sz@sunny.example",
        "country": "China",
        "city": "Shenzhen",
        "address_line": "No. 88 Textile Road",
        "capacity_month": "180000",
        "status": "Active",
        "note": "Demo factory for high-volume programs.",
    },
    {
        "factory_code": "SUN-BD03",
        "factory_name": "Sunny Apparel Dhaka",
        "short_name": "Sunny BD",
        "contact_person": "Mr. Rahman",
        "phone": "+880 2 5555 0303",
        "email": "factory.bd@sunny.example",
        "country": "Bangladesh",
        "city": "Dhaka",
        "address_line": "Sector 7, Export Processing Zone",
        "capacity_month": "150000",
        "status": "Active",
        "note": "Demo factory for value programs.",
    },
]


def _production_now_text() -> str:
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")


def _safe_float_value(value: object) -> float:
    text = str(value or "").strip().replace(",", "").replace("%", "")
    if not text:
        return 0.0
    try:
        return float(text)
    except Exception:
        return 0.0


def _format_number(value: float) -> str:
    numeric = round(float(value or 0.0), 4)
    if abs(numeric - round(numeric)) < 1e-9:
        return str(int(round(numeric)))
    return f"{numeric:.4f}".rstrip("0").rstrip(".")


def _excel_number(value: object) -> int | float | str:
    numeric = round(_safe_float_value(value), 4)
    if abs(numeric) < 1e-9:
        return 0
    if abs(numeric - round(numeric)) < 1e-9:
        return int(round(numeric))
    return numeric


def default_production_order_payload() -> dict:
    return {
        "record_id": "",
        "source_type": "",
        "source_order_id": "",
        "source_item_key": "",
        "image_path": "",
        "created_at": "",
        "production_order": "",
        "factory": "",
        "mr_pic": "",
        "buyer": "",
        "style": "",
        "parent": "",
        "season": "",
        "po_number": "",
        "dept_number": "",
        "store_number": "",
        "po_date": "",
        "po_time": "",
        "ship_date": "",
        "cancel_date": "",
        "ex_fty_date_plan": "",
        "actual_ex_fty": "",
        "color": "",
        "size_range": "",
        "size_scale": "",
        "order_qty": "",
        "ship_qty": "",
        "status": "draft",
        "over_short_ship_qty": "",
        "over_short_ship_percent": "",
        "final_inspection_date": "",
        "actual_cut_qty": "",
        "carton_qty": "",
        "odd_carton_qty": "",
        "unit_per_carton": "",
        "carton_dimension": "",
        "odd_carton_dimension": "",
        "cbm": "",
        "net_weight": "",
        "gross_weight": "",
        "color_quantity_json": "",
        "updated_at": "",
        "latest_user": "",
        "notes": "",
        "materials_json": "",
    }


def default_production_factory_payload() -> dict:
    return {
        "factory_id": "",
        "factory_code": "",
        "factory_name": "",
        "short_name": "",
        "contact_person": "",
        "phone": "",
        "email": "",
        "country": "",
        "city": "",
        "address_line": "",
        "capacity_month": "",
        "status": "Active",
        "created_at": "",
        "updated_at": "",
        "note": "",
    }


def normalize_production_factory_row(payload: object) -> dict | None:
    if not isinstance(payload, dict):
        return None
    normalized = default_production_factory_payload()
    for key in normalized:
        normalized[key] = str(payload.get(key, normalized[key]) or "").strip()
    normalized["factory_id"] = normalized["factory_id"] or secrets.token_hex(16)
    normalized["factory_code"] = normalized["factory_code"].upper()
    status = normalized["status"].strip().lower()
    status_map = {item.lower(): item for item in PRODUCTION_FACTORY_STATUS_OPTIONS}
    normalized["status"] = status_map.get(status, "Active")
    if not normalized["created_at"]:
        normalized["created_at"] = _production_now_text()
    if not normalized["updated_at"]:
        normalized["updated_at"] = normalized["created_at"]
    return normalized


def _normalize_production_factory_rows(payload: object) -> list[dict]:
    if not isinstance(payload, list):
        return []
    rows: list[dict] = []
    for item in payload:
        normalized = normalize_production_factory_row(item)
        if isinstance(normalized, dict):
            rows.append(normalized)
    return rows


def _production_demo_factory_rows() -> list[dict]:
    rows: list[dict] = []
    for item in PRODUCTION_FACTORY_DEMO_ROWS:
        normalized = normalize_production_factory_row(item)
        if isinstance(normalized, dict):
            rows.append(normalized)
    return rows


def default_production_packing_list_assets() -> dict[str, object]:
    return {"template_url": PRODUCTION_PACKING_LIST_TEMPLATE_URL}


def default_production_carton_sticker_assets() -> dict[str, object]:
    return {"template_url": PRODUCTION_CARTON_STICKER_TEMPLATE_URL}


def normalize_production_order_row(payload: object) -> dict | None:
    if not isinstance(payload, dict):
        return None
    normalized = default_production_order_payload()
    for key in normalized:
        normalized[key] = str(payload.get(key, normalized[key]) or "").strip()
    normalized["record_id"] = normalized["record_id"] or secrets.token_hex(16)
    normalized["style"] = normalize_style_identifier(normalized.get("style"))
    normalized["status"] = str(normalized.get("status") or "draft").strip().lower() or "draft"
    if normalized["status"] not in PRODUCTION_STATUS_OPTIONS:
        normalized["status"] = "draft"
    if not normalized["created_at"]:
        normalized["created_at"] = _production_now_text()
    if not normalized["updated_at"]:
        normalized["updated_at"] = normalized["created_at"]
    if not normalized["production_order"]:
        normalized["production_order"] = f"PROD-{normalized['record_id'][:8].upper()}"
    _recalculate_production_balance(normalized)
    _recalculate_production_packing(normalized)
    return normalized


def _recalculate_production_balance(row: dict) -> None:
    order_qty = _safe_float_value(row.get("order_qty"))
    ship_qty = _safe_float_value(row.get("ship_qty"))
    if not order_qty and not ship_qty:
        return
    diff = ship_qty - order_qty
    row["over_short_ship_qty"] = _format_number(diff)
    if order_qty:
        row["over_short_ship_percent"] = f"{_format_number(diff / order_qty * 100)}%"


def _recalculate_production_packing(row: dict) -> None:
    ship_qty = _safe_float_value(row.get("ship_qty"))
    unit_per_carton = _safe_float_value(row.get("unit_per_carton"))
    if ship_qty <= 0 or unit_per_carton <= 0:
        row["carton_qty"] = ""
        row["odd_carton_qty"] = ""
        row["odd_carton_dimension"] = ""
        return
    full_cartons = int(ship_qty // unit_per_carton)
    odd_qty = ship_qty - (full_cartons * unit_per_carton)
    row["carton_qty"] = str(full_cartons)
    row["odd_carton_qty"] = _format_number(odd_qty)
    if odd_qty <= 0:
        row["odd_carton_dimension"] = ""
    elif odd_qty >= unit_per_carton / 2:
        row["odd_carton_dimension"] = "60 x 48 x 25 (cm)"
    else:
        row["odd_carton_dimension"] = "60 x 48 x 15 (cm)"


def _normalize_production_rows(payload: object) -> list[dict]:
    if not isinstance(payload, list):
        return []
    rows: list[dict] = []
    for item in payload:
        normalized = normalize_production_order_row(item)
        if isinstance(normalized, dict):
            rows.append(normalized)
    return rows


def _production_style_season_key(row: dict) -> tuple[str, str]:
    style = normalize_style_identifier(row.get("style"))
    season = " ".join(str(row.get("season", "") or "").strip().lower().split())
    return (style, season)


def _production_row_updated_sort_value(row: dict) -> str:
    return str(row.get("updated_at", "") or row.get("created_at", "") or "").strip()


def _production_shared_fields_from_row(row: dict) -> dict[str, str]:
    return {
        key: str(row.get(key, "") or "").strip()
        for key in PRODUCTION_STYLE_SEASON_SHARED_KEYS
    }


def _apply_production_shared_fields(row: dict, shared_values: dict[str, str], *, updated_at: str = "") -> dict:
    merged = dict(row)
    for key in PRODUCTION_STYLE_SEASON_SHARED_KEYS:
        merged[key] = str(shared_values.get(key, "") or "").strip()
    if updated_at:
        merged["updated_at"] = updated_at
    _recalculate_production_packing(merged)
    return normalize_production_order_row(merged) or merged


def _production_saved_shared_fields_by_style_season(saved_rows: list[dict]) -> dict[tuple[str, str], dict[str, str]]:
    grouped: dict[tuple[str, str], dict[str, str]] = {}
    for row in sorted(saved_rows, key=_production_row_updated_sort_value):
        style_season_key = _production_style_season_key(row)
        if not style_season_key[0]:
            continue
        values = _production_shared_fields_from_row(row)
        if any(values.values()):
            grouped[style_season_key] = values
    return grouped


def load_production_rows_from_source(self) -> list[dict]:
    self.production_source_initialized = False
    _append_production_debug_log(
        "load-source start "
        f"use_server={self.should_use_server_data_source()} "
        f"data_mode={getattr(self, 'server_settings', {}).get('data_mode', '') if isinstance(getattr(self, 'server_settings', {}), dict) else ''} "
        f"db_path={DB_PATH}"
    )
    if self.should_use_server_data_source():
        try:
            payload = fetch_app_setting(self.server_settings, PRODUCTION_APP_SETTING_KEY, None)
            self.production_source_initialized = isinstance(payload, list)
            rows = _normalize_production_rows(payload)
            _append_production_debug_log(
                f"load-source server initialized={self.production_source_initialized} rows={len(rows)} payload_type={type(payload).__name__}"
            )
            if rows:
                return rows
            local_payload = get_app_setting(DB_PATH, PRODUCTION_APP_SETTING_KEY, None)
            local_rows = _normalize_production_rows(local_payload)
            _append_production_debug_log(
                f"load-source server empty fallback local initialized={isinstance(local_payload, list)} "
                f"rows={len(local_rows)} payload_type={type(local_payload).__name__}"
            )
            if local_rows:
                self.production_source_initialized = True
                self.production_source_is_local_fallback = True
                return local_rows
        except Exception as exc:
            _append_production_debug_log(f"load-source server failed: {exc}")
    payload = get_app_setting(DB_PATH, PRODUCTION_APP_SETTING_KEY, None)
    self.production_source_initialized = isinstance(payload, list)
    rows = _normalize_production_rows(payload)
    _append_production_debug_log(
        f"load-source local initialized={self.production_source_initialized} rows={len(rows)} payload_type={type(payload).__name__}"
    )
    return rows


def save_production_rows_to_source(self, rows: list[dict]) -> list[dict]:
    normalized_rows = _normalize_production_rows(rows)
    self.production_source_initialized = True
    _append_production_debug_log(
        f"save-source start rows={len(normalized_rows)} use_server={self.should_use_server_data_source()}"
    )
    if self.should_use_server_data_source():
        saved = _normalize_production_rows(save_app_setting(self.server_settings, PRODUCTION_APP_SETTING_KEY, normalized_rows))
        _append_production_debug_log(f"save-source server done rows={len(saved)}")
        return saved
    saved = _normalize_production_rows(set_app_setting(DB_PATH, PRODUCTION_APP_SETTING_KEY, normalized_rows))
    _append_production_debug_log(f"save-source local done rows={len(saved)}")
    return saved


def _compact_production_saved_detail_row(row: dict) -> dict:
    compact: dict[str, str] = {}
    for key in PRODUCTION_SAVED_DETAIL_KEYS:
        value = str(row.get(key, "") or "").strip()
        if value or key == "record_id":
            compact[key] = value
    return compact


def save_production_saved_detail_rows_to_source(self, rows: list[dict]) -> list[dict]:
    compact_rows = [
        _compact_production_saved_detail_row(row)
        for row in list(rows or [])
        if isinstance(row, dict) and str(row.get("record_id", "") or "").strip()
    ]
    _append_production_debug_log(
        f"save-detail-overlays start rows={len(compact_rows)} use_server={self.should_use_server_data_source()}"
    )
    if self.should_use_server_data_source():
        saved = _normalize_production_rows(save_app_setting(self.server_settings, PRODUCTION_APP_SETTING_KEY, compact_rows))
        _append_production_debug_log(f"save-detail-overlays server done rows={len(saved)}")
        return saved
    saved = _normalize_production_rows(set_app_setting(DB_PATH, PRODUCTION_APP_SETTING_KEY, compact_rows))
    _append_production_debug_log(f"save-detail-overlays local done rows={len(saved)}")
    return saved


def save_production_detail_row_to_source(self, row: dict) -> dict:
    normalized = normalize_production_order_row(row)
    if not isinstance(normalized, dict):
        return {}
    record_id = str(normalized.get("record_id", "") or "").strip()
    if not record_id:
        return {}
    style_season_key = _production_style_season_key(normalized)
    shared_values = _production_shared_fields_from_row(normalized)
    updated_at = str(normalized.get("updated_at", "") or "").strip() or _production_now_text()
    current_rows = self.load_production_rows_from_source()
    known_rows_by_id: dict[str, dict] = {}
    for source_row in list(getattr(self, "production_rows", []) or []) + list(current_rows or []):
        if not isinstance(source_row, dict):
            continue
        source_id = str(source_row.get("record_id", "") or "").strip()
        if source_id:
            known_rows_by_id[source_id] = dict(source_row)
    known_rows_by_id[record_id] = dict(normalized)
    merged_rows: list[dict] = []
    written_ids: set[str] = set()
    for existing_row in list(current_rows or []):
        existing_id = str(existing_row.get("record_id", "") or "").strip()
        if not existing_id:
            continue
        if existing_id == record_id:
            merged_rows.append(normalized)
            written_ids.add(existing_id)
            continue
        if style_season_key[0] and _production_style_season_key(existing_row) == style_season_key:
            merged_rows.append(_apply_production_shared_fields(dict(existing_row), shared_values, updated_at=updated_at))
            written_ids.add(existing_id)
        else:
            merged_rows.append(dict(existing_row))
            written_ids.add(existing_id)
    for known_id, known_row in known_rows_by_id.items():
        if known_id in written_ids:
            continue
        if known_id == record_id:
            merged_rows.append(normalized)
            written_ids.add(known_id)
            continue
        if style_season_key[0] and _production_style_season_key(known_row) == style_season_key:
            merged_rows.append(_apply_production_shared_fields(dict(known_row), shared_values, updated_at=updated_at))
            written_ids.add(known_id)
    if record_id not in written_ids:
        merged_rows.append(normalized)
    saved_rows = self.save_production_saved_detail_rows_to_source(merged_rows)
    return next((dict(item) for item in saved_rows if str(item.get("record_id", "") or "").strip() == record_id), normalized)


def delete_production_detail_rows_from_source(self, record_ids: set[str]) -> None:
    target_ids = {str(item or "").strip() for item in record_ids if str(item or "").strip()}
    if not target_ids:
        return
    remaining_rows = [
        row
        for row in self.load_production_rows_from_source()
        if str(row.get("record_id", "") or "").strip() not in target_ids
    ]
    self.save_production_saved_detail_rows_to_source(remaining_rows)


def load_production_factory_rows_from_source(self) -> list[dict]:
    rows: list[dict] = []
    if self.should_use_server_data_source():
        try:
            payload = fetch_app_setting(self.server_settings, PRODUCTION_FACTORY_APP_SETTING_KEY, [])
            rows = _normalize_production_factory_rows(payload)
        except Exception:
            rows = []
    if not rows:
        payload = get_app_setting(DB_PATH, PRODUCTION_FACTORY_APP_SETTING_KEY, [])
        rows = _normalize_production_factory_rows(payload)
    if rows:
        return rows
    demo_rows = _production_demo_factory_rows()
    if demo_rows:
        return save_production_factory_rows_to_source(self, demo_rows)
    return []


def save_production_factory_rows_to_source(self, rows: list[dict]) -> list[dict]:
    normalized_rows = _normalize_production_factory_rows(rows)
    if self.should_use_server_data_source():
        try:
            saved = _normalize_production_factory_rows(
                save_app_setting(self.server_settings, PRODUCTION_FACTORY_APP_SETTING_KEY, normalized_rows)
            )
            if saved:
                return saved
        except Exception:
            pass
    return _normalize_production_factory_rows(set_app_setting(DB_PATH, PRODUCTION_FACTORY_APP_SETTING_KEY, normalized_rows))


def save_production_factory_row_to_source(self, row: dict) -> dict:
    normalized = normalize_production_factory_row(row)
    if not isinstance(normalized, dict):
        return {}
    current_rows = self.load_production_factory_rows_from_source()
    factory_id = str(normalized.get("factory_id", "")).strip()
    rows: list[dict] = []
    replaced = False
    for existing_row in current_rows:
        if str(existing_row.get("factory_id", "")).strip() == factory_id:
            rows.append(normalized)
            replaced = True
        else:
            rows.append(dict(existing_row))
    if not replaced:
        rows.append(normalized)
    saved_rows = self.save_production_factory_rows_to_source(rows)
    return next((dict(item) for item in saved_rows if str(item.get("factory_id", "")).strip() == factory_id), normalized)


def delete_production_factory_row_from_source(self, factory_id: str) -> None:
    normalized_id = str(factory_id or "").strip()
    if not normalized_id:
        return
    remaining = [
        row
        for row in self.load_production_factory_rows_from_source()
        if str(row.get("factory_id", "")).strip() != normalized_id
    ]
    self.save_production_factory_rows_to_source(remaining)


def get_active_production_factory_names(self) -> list[str]:
    rows = list(getattr(self, "production_factory_rows", []) or [])
    if not rows:
        rows = self.load_production_factory_rows_from_source()
        self.production_factory_rows = rows
    names = []
    seen: set[str] = set()
    for row in rows:
        if str(row.get("status", "")).strip().lower() != "active":
            continue
        name = str(row.get("factory_name", "") or row.get("short_name", "") or row.get("factory_code", "") or "").strip()
        if not name or name.lower() in seen:
            continue
        seen.add(name.lower())
        names.append(name)
    return sorted(names, key=str.lower)


def _production_saved_row_map(self) -> dict[str, dict]:
    rows = self.load_production_rows_from_source()
    return {
        str(row.get("record_id", "")).strip(): dict(row)
        for row in rows
        if str(row.get("record_id", "")).strip()
    }


def _merge_production_saved_fields(row: dict, saved_row: dict | None) -> dict:
    if not isinstance(saved_row, dict):
        return row
    merged = dict(row)
    merge_keys = {
        "factory",
        "mr_pic",
        "ex_fty_date_plan",
        "actual_ex_fty",
        "ship_qty",
        "status",
        "final_inspection_date",
        "carton_qty",
        "odd_carton_qty",
        "unit_per_carton",
        "carton_dimension",
        "odd_carton_dimension",
        "cbm",
        "net_weight",
        "gross_weight",
        "color_quantity_json",
        "notes",
        "materials_json",
    }
    for key in merge_keys:
        saved_value = str(saved_row.get(key, "") or "").strip()
        if saved_value:
            merged[key] = saved_value
    if str(saved_row.get("updated_at", "") or "").strip():
        merged["updated_at"] = str(saved_row.get("updated_at", "") or "").strip()
    _recalculate_production_balance(merged)
    return merged


def _production_load_materials_json(value: object) -> list[dict]:
    text = str(value or "").strip()
    if not text:
        return []
    try:
        payload = json.loads(text)
    except Exception:
        return []
    if not isinstance(payload, list):
        return []
    return [dict(item) for item in payload if isinstance(item, dict)]


def _production_dump_materials_json(rows: list[dict]) -> str:
    compact_rows: list[dict[str, str]] = []
    for row in list(rows or []):
        if not isinstance(row, dict):
            continue
        compact = {
            key: str(row.get(key, "") or "").strip()
            for key in PRODUCTION_MATERIAL_STORAGE_KEYS
            if str(row.get(key, "") or "").strip()
        }
        if compact:
            compact_rows.append(compact)
    return json.dumps(compact_rows, ensure_ascii=False, separators=(",", ":")) if compact_rows else ""


def _production_order_line_items(order: dict) -> list[dict]:
    raw_payload = order.get("raw_json")
    parsed_payload = {}
    if isinstance(raw_payload, str) and raw_payload.strip():
        try:
            parsed_payload = json.loads(raw_payload)
        except Exception:
            parsed_payload = {}
    if not isinstance(parsed_payload, dict):
        return []
    for key in ("items", "line_items"):
        items = parsed_payload.get(key, [])
        if isinstance(items, list):
            return [dict(item) for item in items if isinstance(item, dict)]
    return []


def _production_items_for_style(order: dict, style: str) -> list[dict]:
    target_style = normalize_style_identifier(style)
    items = _production_order_line_items(order)
    if not target_style:
        return items
    matched_items = [
        item
        for item in items
        if normalize_style_identifier(item.get("mfg_style") or item.get("style_code")) == target_style
    ]
    return matched_items or items


def _production_style_size_summary(self, order: dict, style: str) -> tuple[str, str]:
    items = [
        item
        for item in _production_items_for_style(order, style)
        if str(item.get("size_desc", "") or "").strip()
    ]
    if not items:
        return (str(order.get("size_range", "") or ""), str(order.get("size_scale", "") or ""))
    raw_sizes = [str(item.get("size_desc", "") or "").strip() for item in items]
    if hasattr(self, "sort_size_codes"):
        ordered_sizes = self.sort_size_codes(raw_sizes)
    else:
        ordered_sizes = []
        seen: set[str] = set()
        for raw_size in raw_sizes:
            size_code = str(raw_size or "").strip().upper().replace(" ", "")
            if size_code and size_code not in seen:
                seen.add(size_code)
                ordered_sizes.append(size_code)
    size_ratio_map: dict[str, str] = {}
    for item in items:
        size_code = self.normalize_size_code(item.get("size_desc")) if hasattr(self, "normalize_size_code") else str(item.get("size_desc", "") or "").strip().upper().replace(" ", "")
        if not size_code or size_code in size_ratio_map:
            continue
        size_ratio_map[size_code] = str(item.get("pack_qty", "") or "").strip() or "-"
    return (
        "-".join(ordered_sizes),
        "-".join(size_ratio_map.get(size_code, "-") for size_code in ordered_sizes),
    )


def _production_style_color_summary(order: dict, style: str) -> str:
    colors: list[str] = []
    seen: set[str] = set()
    for item in _production_items_for_style(order, style):
        color = str(item.get("mfg_color") or item.get("color") or item.get("color_label") or "").strip()
        if not color or color.lower() in seen:
            continue
        seen.add(color.lower())
        colors.append(color)
    return ", ".join(colors)


def _production_style_order_qty(order: dict, style: str) -> str:
    total = 0.0
    has_total = False
    for item in _production_items_for_style(order, style):
        item_total = _safe_float_value(item.get("total_units"))
        if item_total:
            total += item_total
            has_total = True
    if has_total:
        return _format_number(total)
    return str(order.get("total_qty", "") or "").strip()


def _production_detail_order_payload(self, production_row: dict) -> dict:
    source_order_id = str(production_row.get("source_order_id", "") or "").strip()
    if source_order_id and source_order_id.isdigit() and hasattr(self, "fetch_order_detail_from_source"):
        try:
            detail = self.fetch_order_detail_from_source(int(source_order_id))
            if isinstance(detail, dict):
                return detail
        except Exception:
            pass
    po_number = str(production_row.get("po_number", "") or "").strip()
    for candidate in list(getattr(self, "all_order_versions", []) or []) + list(getattr(self, "all_orders", []) or []):
        if not isinstance(candidate, dict):
            continue
        if source_order_id and str(candidate.get("id", "") or "").strip() == source_order_id:
            return {"header": dict(candidate), "items": _production_order_line_items(candidate)}
        if po_number and str(candidate.get("po_number", "") or "").strip() == po_number:
            return {"header": dict(candidate), "items": _production_order_line_items(candidate)}
    cached_payload = self.load_main_ui_session_cache("purchase_order") if hasattr(self, "load_main_ui_session_cache") else None
    if isinstance(cached_payload, dict):
        for payload_key in ("all_order_versions", "order_versions", "all_orders"):
            for candidate in list(cached_payload.get(payload_key, []) or []):
                if not isinstance(candidate, dict):
                    continue
                if source_order_id and str(candidate.get("id", "") or "").strip() == source_order_id:
                    return {"header": dict(candidate), "items": _production_order_line_items(candidate)}
                if po_number and str(candidate.get("po_number", "") or "").strip() == po_number:
                    return {"header": dict(candidate), "items": _production_order_line_items(candidate)}
    return {"header": dict(production_row), "items": []}


def get_production_po_detail_line_items(self, production_row: dict) -> list[dict]:
    detail = _production_detail_order_payload(self, production_row)
    items = [dict(item) for item in list(detail.get("items", []) or []) if isinstance(item, dict)]
    style = normalize_style_identifier(production_row.get("style"))
    if not style:
        return items
    matched = [
        item
        for item in items
        if normalize_style_identifier(item.get("mfg_style") or item.get("style_code")) == style
    ]
    return matched or items


def production_unit_per_pack(self, production_row: dict) -> str:
    total = 0.0
    has_value = False
    for item in self.get_production_po_detail_line_items(production_row):
        value = _safe_float_value(item.get("pack_qty"))
        if value:
            total += value
            has_value = True
    return _format_number(total) if has_value else "0"


def _production_matching_tech_pack_record(self, style: object) -> dict:
    normalized_style = normalize_style_identifier(style)
    if not normalized_style:
        return {}

    def find(rows: object) -> dict:
        for item in list(rows or []):
            if not isinstance(item, dict):
                continue
            if normalize_style_identifier(item.get("style_code")) == normalized_style:
                return dict(item)
        return {}

    if hasattr(self, "load_tech_pack_library_from_source"):
        should_refresh_source = True
        if hasattr(self, "should_use_server_data_source"):
            try:
                should_refresh_source = bool(self.should_use_server_data_source())
            except Exception:
                should_refresh_source = True
        if should_refresh_source:
            try:
                rows = [dict(row) for row in list(self.load_tech_pack_library_from_source() or []) if isinstance(row, dict)]
                if rows:
                    self.tech_pack_library = rows
                matched = find(rows)
                if matched:
                    return matched
            except Exception as exc:
                _append_production_debug_log(f"materials refresh tech-pack source failed: {exc}")

    for attr_name in ("tech_pack_library", "tech_pack_rows"):
        matched = find(getattr(self, attr_name, []))
        if matched:
            return matched
    if hasattr(self, "load_main_ui_session_cache"):
        for cache_scope in ("tech_pack", "production", "bom"):
            cached_payload = self.load_main_ui_session_cache(cache_scope)
            if not isinstance(cached_payload, dict):
                continue
            for payload_key in ("tech_pack_library", "tech_pack_rows"):
                matched = find(cached_payload.get(payload_key, []))
                if matched:
                    return matched
    if hasattr(self, "load_tech_pack_library_from_source"):
        try:
            rows = [dict(row) for row in list(self.load_tech_pack_library_from_source() or []) if isinstance(row, dict)]
            if rows and not getattr(self, "tech_pack_library", None):
                self.tech_pack_library = rows
            matched = find(rows)
            if matched:
                return matched
        except Exception as exc:
            _append_production_debug_log(f"materials load tech-pack source failed: {exc}")
    return {}


def _production_consumption_versions_for_style(self, style: object) -> list[dict]:
    record = _production_matching_tech_pack_record(self, style)
    if not record:
        return []
    if hasattr(self, "get_tech_pack_consumption_versions"):
        try:
            return [dict(item) for item in list(self.get_tech_pack_consumption_versions(record) or []) if isinstance(item, dict)]
        except Exception as exc:
            _append_production_debug_log(f"materials get consumption versions failed: {exc}")
    return [dict(item) for item in list(record.get("consumption_versions", []) or []) if isinstance(item, dict)]


_PRODUCTION_LENGTH_UOM_FACTORS_TO_M = {
    "MM": 0.001,
    "CM": 0.01,
    "M": 1.0,
    "INCH": 0.0254,
    "YARD": 0.9144,
}


def _production_material_line_is_thread(line: dict) -> bool:
    section = str(line.get("section", "") or "").strip().lower()
    item_name = str(line.get("bom_item_name", "") or line.get("item_name", "") or "").strip().lower()
    return section == "thread" or "thread" in item_name


_PRODUCTION_COMMON_MATERIAL_COLORS = {
    "",
    "-",
    "--",
    "ALL",
    "ASSORTED",
    "CLEAR",
    "DTM",
    "MIX",
    "MIXED",
    "MULTI",
    "N/A",
    "NA",
    "NO COLOR",
    "NONE",
}


def _production_normalize_color_token(value: object) -> str:
    text = str(value or "").strip().upper()
    if not text:
        return ""
    text = re.sub(r"[^A-Z0-9]+", " ", text)
    return re.sub(r"\s+", " ", text).strip()


def _production_color_tokens_from_value(value: object) -> set[str]:
    text = str(value or "").strip()
    if not text:
        return set()
    parts = re.split(r"[,;|]+", text)
    tokens: set[str] = set()
    for part in parts:
        token = _production_normalize_color_token(part)
        if token and token not in _PRODUCTION_COMMON_MATERIAL_COLORS:
            tokens.add(token)
    return tokens


def _production_style_tokens_from_value(value: object) -> set[str]:
    return {
        normalize_style_identifier(part)
        for part in re.split(r"[,;|]+", str(value or ""))
        if normalize_style_identifier(part)
    }


def _production_strict_items_for_style(order: dict, normalized_style: str) -> list[dict]:
    if not normalized_style:
        return []
    return [
        dict(item)
        for item in _production_order_line_items(order)
        if isinstance(item, dict)
        and normalize_style_identifier(item.get("mfg_style") or item.get("style_code")) == normalized_style
    ]


def _production_order_color_tokens(self, production_row: dict) -> set[str]:
    colors: set[str] = set()
    for key in ("color", "mfg_color", "color_label"):
        colors.update(_production_color_tokens_from_value(production_row.get(key)))
    if hasattr(self, "get_production_po_detail_line_items"):
        try:
            line_items = self.get_production_po_detail_line_items(production_row)
        except Exception:
            line_items = []
        for item in list(line_items or []):
            if not isinstance(item, dict):
                continue
            for key in ("mfg_color", "color", "color_label"):
                colors.update(_production_color_tokens_from_value(item.get(key)))
    return colors


def _production_order_row_matches_style(row: dict, normalized_style: str) -> bool:
    if not normalized_style:
        return False
    for key in ("style", "style_code", "mfg_style"):
        if normalized_style in _production_style_tokens_from_value(row.get(key)):
            return True
    return any(
        normalize_style_identifier(item.get("mfg_style") or item.get("style_code")) == normalized_style
        for item in _production_order_line_items(row)
        if isinstance(item, dict)
    )


def _production_style_po_color_tokens(self, style: object) -> set[str]:
    normalized_style = normalize_style_identifier(style)
    if not normalized_style:
        return set()
    source_rows: list[dict] = []
    for attr_name in ("all_order_versions", "all_orders"):
        source_rows.extend(
            dict(row)
            for row in list(getattr(self, attr_name, []) or [])
            if isinstance(row, dict)
        )
    if not source_rows and hasattr(self, "load_main_ui_session_cache"):
        cached_payload = self.load_main_ui_session_cache("purchase_order")
        if isinstance(cached_payload, dict):
            for payload_key in ("all_order_versions", "order_versions", "all_orders"):
                source_rows.extend(
                    dict(row)
                    for row in list(cached_payload.get(payload_key, []) or [])
                    if isinstance(row, dict)
                )
    if not source_rows and hasattr(self, "fetch_order_records_from_source"):
        try:
            source_rows.extend(dict(row) for row in list(self.fetch_order_records_from_source() or []) if isinstance(row, dict))
        except Exception as exc:
            _append_production_debug_log(f"materials style color source load failed: {exc}")

    colors: set[str] = set()
    for row in source_rows:
        if not _production_order_row_matches_style(row, normalized_style):
            continue
        matched_items = _production_strict_items_for_style(row, normalized_style)
        if matched_items:
            for item in matched_items:
                for key in ("mfg_color", "color", "color_label"):
                    colors.update(_production_color_tokens_from_value(item.get(key)))
            continue
        for key in ("color", "mfg_color", "color_label"):
            colors.update(_production_color_tokens_from_value(row.get(key)))
    return colors


def _production_material_line_matches_order_color(
    line: dict,
    order_color_tokens: set[str],
    style_color_tokens: set[str] | None = None,
) -> bool:
    if not order_color_tokens:
        return True
    material_color_tokens = _production_color_tokens_from_value(line.get("color"))
    if not material_color_tokens:
        return True
    if style_color_tokens is not None and not material_color_tokens.intersection(style_color_tokens):
        return True
    return bool(material_color_tokens.intersection(order_color_tokens))


def _production_thread_cone_length_meters(line: dict) -> float:
    length_value = _safe_float_value(line.get("length_value"))
    length_unit = str(line.get("length_unit", "") or "").strip().upper() or "M"
    if length_value <= 0:
        length_value = _safe_float_value(line.get("trim_size_um"))
        length_unit = str(line.get("trim_size_unit", "") or "").strip().upper() or "M"
    factor = _PRODUCTION_LENGTH_UOM_FACTORS_TO_M.get(length_unit)
    if factor is None:
        return 0.0
    return length_value * factor


def _production_material_fabric_weight_text(line: dict) -> str:
    fabric_weight = str(line.get("fabric_weight", "") or "").strip()
    if not fabric_weight:
        return ""
    fabric_weight_uom = str(line.get("fabric_weight_uom", "") or "").strip().upper()
    if fabric_weight_uom and fabric_weight_uom not in fabric_weight.upper().split():
        return f"{fabric_weight} {fabric_weight_uom}".strip()
    return fabric_weight


def _split_production_fabric_weight(value: object, fallback_uom: object = "") -> tuple[str, str]:
    text = str(value or "").strip()
    if not text:
        return "", ""
    match = re.search(r"-?\d+(?:\.\d+)?", text.replace(",", ""))
    number_text = _format_number(float(match.group(0))) if match else text
    uom_text = str(fallback_uom or "").strip().upper()
    tail_text = text[match.end():].strip().upper() if match else ""
    tail_text = re.sub(r"[^A-Z]+", "", tail_text)
    if tail_text in {"KG", "KGS"}:
        uom_text = "KG"
    elif tail_text in {"LB", "LBS"}:
        uom_text = "LBS"
    return number_text, uom_text


def sync_production_material_edits_to_tech_pack(self, production_row: dict) -> int:
    style = normalize_style_identifier(production_row.get("style"))
    if not style or not hasattr(self, "save_tech_pack_record_patch_to_source"):
        return 0
    edited_rows = _production_load_materials_json(production_row.get("materials_json"))
    if not edited_rows:
        return 0
    record = _production_matching_tech_pack_record(self, style)
    if not record:
        return 0
    versions = _production_consumption_versions_for_style(self, style)
    changed_lines = 0
    edited_by_line_id = {
        str(row.get("line_id", "") or "").strip(): dict(row)
        for row in edited_rows
        if str(row.get("line_id", "") or "").strip()
    }
    edited_by_item_code = {
        str(row.get("item_code", "") or "").strip(): dict(row)
        for row in edited_rows
        if str(row.get("item_code", "") or "").strip()
    }
    updated_versions: list[dict] = []
    for version in list(versions or []):
        normalized_version = dict(version)
        if str(normalized_version.get("version_type", "") or normalized_version.get("version_id", "")).strip().lower() != "production":
            updated_versions.append(normalized_version)
            continue
        updated_lines: list[dict] = []
        for line in list(normalized_version.get("lines", []) or []):
            if not isinstance(line, dict):
                continue
            updated_line = dict(line)
            edit_row = edited_by_line_id.get(str(line.get("line_id", "") or "").strip())
            if edit_row is None:
                edit_row = edited_by_item_code.get(str(line.get("bom_item_code", "") or line.get("item_code", "") or "").strip())
            if edit_row is not None:
                next_consumption = str(edit_row.get("consumption", "") or "").strip()
                if str(updated_line.get("consumption", "") or "").strip() != next_consumption:
                    updated_line["consumption"] = next_consumption
                    changed_lines += 1
                fabric_weight_text, fabric_weight_uom = _split_production_fabric_weight(
                    edit_row.get("fabric_weight"),
                    updated_line.get("fabric_weight_uom"),
                )
                if str(updated_line.get("fabric_weight", "") or "").strip() != fabric_weight_text:
                    updated_line["fabric_weight"] = fabric_weight_text
                    changed_lines += 1
                if fabric_weight_text and str(updated_line.get("fabric_weight_uom", "") or "").strip().upper() != fabric_weight_uom:
                    updated_line["fabric_weight_uom"] = fabric_weight_uom or "KG"
                    changed_lines += 1
                if not fabric_weight_text and str(updated_line.get("fabric_weight_uom", "") or "").strip():
                    updated_line["fabric_weight_uom"] = ""
                    changed_lines += 1
            updated_lines.append(updated_line)
        normalized_version["lines"] = updated_lines
        updated_versions.append(normalized_version)
    if not changed_lines:
        return 0
    saved_record = self.save_tech_pack_record_patch_to_source(style, {"consumption_versions": updated_versions})
    if isinstance(saved_record, dict) and saved_record:
        library_by_style = {
            normalize_style_identifier(item.get("style_code")): dict(item)
            for item in list(getattr(self, "tech_pack_library", []) or [])
            if isinstance(item, dict) and normalize_style_identifier(item.get("style_code"))
        }
        library_by_style[style] = dict(saved_record)
        self.tech_pack_library = list(library_by_style.values())
    return changed_lines


def build_production_material_rows_from_consumption(self, production_row: dict) -> list[dict]:
    style = normalize_style_identifier(production_row.get("style"))
    base_qty = _safe_float_value(production_row.get("ship_qty")) or _safe_float_value(production_row.get("order_qty"))
    versions = _production_consumption_versions_for_style(self, style)
    production_version = next(
        (
            dict(version)
            for version in versions
            if str(version.get("version_type", "") or version.get("version_id", "")).strip().lower() == "production"
        ),
        {},
    )
    lines = [dict(item) for item in list(production_version.get("lines", []) or []) if isinstance(item, dict)]
    order_color_tokens = _production_order_color_tokens(self, production_row)
    style_color_tokens = _production_style_po_color_tokens(self, style)
    material_rows: list[dict] = []
    for index, line in enumerate(lines, start=1):
        if not _production_material_line_matches_order_color(line, order_color_tokens, style_color_tokens):
            continue
        consumption_value = _safe_float_value(line.get("consumption"))
        waste_percent = _safe_float_value(line.get("waste_percent"))
        required_qty = base_qty * consumption_value * (1 + waste_percent / 100)
        if (
            _production_material_line_is_thread(line)
            and str(line.get("uom", "") or "").strip().upper() == "CONE"
            and required_qty > 0
        ):
            cone_length_meters = _production_thread_cone_length_meters(line)
            if cone_length_meters > 0:
                required_qty = float(math.ceil(required_qty / cone_length_meters))
        material_rows.append(
            {
                "line_id": str(line.get("line_id", "") or "").strip(),
                "costing_id": str(line.get("costing_id", "") or "").strip(),
                "item_code": str(line.get("bom_item_code", "") or line.get("item_code", "") or "").strip(),
                "item_name": str(line.get("bom_item_name", "") or line.get("item_name", "") or "").strip(),
                "type": str(line.get("fabric_type", "") or line.get("type", "") or "").strip(),
                "section": str(line.get("section", "") or "").strip(),
                "color": str(line.get("color", "") or "").strip(),
                "consumption": str(line.get("consumption", "") or "").strip(),
                "uom": str(line.get("uom", "") or "").strip(),
                "waste_percent": str(line.get("waste_percent", "") or "").strip(),
                "required_qty": _format_number(required_qty) if consumption_value and base_qty else "",
                "fabric_weight": _production_material_fabric_weight_text(line),
                "note": f"Production consumption line {index}",
            }
        )
    if material_rows:
        return material_rows
    return _production_load_materials_json(production_row.get("materials_json"))


def _production_is_missing_text(value: object) -> bool:
    text = str(value or "").strip()
    return not text or text in {"-", "--", "N/A", "n/a"}


def _production_resolve_season(self, order: dict, style: str) -> str:
    for key in ("season", "season_display"):
        value = str(order.get(key, "") or "").strip()
        if not _production_is_missing_text(value):
            return value
    if hasattr(self, "get_style_season"):
        value = str(self.get_style_season(style) or "").strip()
        if not _production_is_missing_text(value):
            return value
    cached_lookup = self.build_cached_style_season_lookup() if hasattr(self, "build_cached_style_season_lookup") else {}
    if isinstance(cached_lookup, dict):
        value = str(cached_lookup.get(normalize_style_identifier(style), "") or "").strip()
        if not _production_is_missing_text(value):
            return value
    return ""


def _production_parent_from_tech_pack_row(row: dict, normalized_style: str) -> str:
    parent_summary = str(row.get("parent_summary", "") or "").strip()
    if parent_summary:
        return parent_summary
    overview_data = row.get("overview_data", {})
    if not isinstance(overview_data, dict):
        overview_data = {}
    lead_style_value = str(overview_data.get("lead_style_no", "") or "").strip()
    normalized_lead_style = normalize_style_identifier(lead_style_value)
    if lead_style_value.lower() == "lead" or normalized_lead_style == normalized_style:
        return "Lead"
    return normalized_lead_style


def _production_cached_style_parent_lookup(self) -> dict[str, str]:
    lookup: dict[str, str] = {}

    def add(row: dict) -> None:
        if not isinstance(row, dict):
            return
        style_code = normalize_style_identifier(row.get("style_code"))
        if not style_code or style_code in lookup:
            return
        parent = _production_parent_from_tech_pack_row(row, style_code)
        if parent:
            lookup[style_code] = parent

    for payload_key in ("tech_pack_rows", "tech_pack_library"):
        for row in list(getattr(self, payload_key, []) or []):
            add(row)

    if hasattr(self, "load_main_ui_session_cache"):
        for cache_scope in ("tech_pack", "production", "bom"):
            cached_payload = self.load_main_ui_session_cache(cache_scope)
            if not isinstance(cached_payload, dict):
                continue
            for payload_key in ("tech_pack_rows", "tech_pack_library"):
                for row in list(cached_payload.get(payload_key, []) or []):
                    add(row)

    if not lookup and hasattr(self, "load_tech_pack_library_from_source"):
        try:
            rows = [dict(row) for row in list(self.load_tech_pack_library_from_source() or []) if isinstance(row, dict)]
            if rows and not getattr(self, "tech_pack_library", None):
                self.tech_pack_library = rows
            for row in rows:
                add(row)
        except Exception as exc:
            _append_production_debug_log(f"parent lookup load tech-pack source failed: {exc}")

    return lookup


def _production_resolve_parent(self, style: str, parent_lookup: dict[str, str] | None = None) -> str:
    normalized_style = normalize_style_identifier(style)
    if not normalized_style:
        return ""
    lookup = parent_lookup if isinstance(parent_lookup, dict) else _production_cached_style_parent_lookup(self)
    return str(lookup.get(normalized_style, "") or "").strip()


def _production_po_display_source_rows(self) -> list[dict]:
    if getattr(self, "all_orders", None):
        rows = [dict(item) for item in list(getattr(self, "all_orders", []) or []) if isinstance(item, dict)]
        _append_production_debug_log(f"build-from-po using current all_orders rows={len(rows)}")
        return rows

    cached_payload = self.load_main_ui_session_cache("purchase_order") if hasattr(self, "load_main_ui_session_cache") else None
    active_prefixes = self.get_active_collection_prefixes() if hasattr(self, "get_active_collection_prefixes") else set()
    if isinstance(cached_payload, dict):
        if isinstance(cached_payload.get("all_order_versions"), list):
            version_rows = [
                dict(row)
                for row in list(cached_payload.get("all_order_versions", []) or [])
                if isinstance(row, dict)
            ]
            rows = self.build_purchase_order_style_display_rows(self.extract_latest_purchase_order_versions(version_rows))
            _append_production_debug_log(f"build-from-po using purchase_order cache all_order_versions={len(version_rows)} rows={len(rows)}")
            return rows
        if isinstance(cached_payload.get("order_versions"), list):
            source_rows = [
                dict(row)
                for row in list(cached_payload.get("order_versions", []) or [])
                if isinstance(row, dict)
            ]
            version_rows = [self.enrich_order_row(row, active_prefixes=active_prefixes) for row in source_rows]
            rows = self.build_purchase_order_style_display_rows(self.extract_latest_purchase_order_versions(version_rows))
            _append_production_debug_log(f"build-from-po using purchase_order cache order_versions={len(source_rows)} rows={len(rows)}")
            return rows
        if isinstance(cached_payload.get("all_orders"), list):
            rows = [
                dict(row)
                for row in list(cached_payload.get("all_orders", []) or [])
                if isinstance(row, dict)
            ]
            _append_production_debug_log(f"build-from-po using purchase_order cache all_orders rows={len(rows)}")
            return rows

    if hasattr(self, "fetch_order_records_from_source"):
        try:
            source_rows = [dict(item) for item in self.fetch_order_records_from_source() if isinstance(item, dict)]
            version_rows = [self.enrich_order_row(row, active_prefixes=active_prefixes) for row in source_rows]
            rows = self.build_purchase_order_style_display_rows(self.extract_latest_purchase_order_versions(version_rows))
            _append_production_debug_log(f"build-from-po fetched source_order_versions={len(source_rows)} rows={len(rows)}")
            return rows
        except Exception as exc:
            _append_production_debug_log(f"build-from-po fetch_order_records_from_source failed: {exc}")

    try:
        source_rows = [dict(item) for item in list_order_records(DB_PATH)]
        version_rows = [self.enrich_order_row(row, active_prefixes=active_prefixes) for row in source_rows]
        rows = self.build_purchase_order_style_display_rows(self.extract_latest_purchase_order_versions(version_rows))
        _append_production_debug_log(f"build-from-po local fallback source_order_versions={len(source_rows)} rows={len(rows)}")
        return rows
    except Exception as exc:
        _append_production_debug_log(f"build-from-po local fallback failed: {exc}")
        return []


def _build_production_row_from_po(self, order: dict, line_index: int, parent_lookup: dict[str, str] | None = None) -> dict:
    header = dict(order)
    style = normalize_style_identifier(header.get("style"))
    base_order_id = self.po_base_order_id(header) if hasattr(self, "po_base_order_id") else int(header.get("id", 0) or 0)
    display_id = str(header.get("po_display_row_id", "") or "").strip() or str(base_order_id or header.get("po_number", "") or line_index)
    safe_style_key = style or str(line_index)
    record_id = f"po-{base_order_id}-{safe_style_key}"
    po_number = str(header.get("po_number", "") or "").strip()
    size_range, size_scale = _production_style_size_summary(self, header, style)
    return normalize_production_order_row(
        {
            "record_id": record_id,
            "source_type": "purchase_order",
            "source_order_id": str(base_order_id or header.get("id", "") or "").strip(),
            "source_item_key": display_id,
            "created_at": str(header.get("created_at", "") or ""),
            "production_order": f"PROD-{po_number}-{style or line_index}",
            "buyer": str(header.get("buyer_name", "") or header.get("buyer", "") or ""),
            "style": style,
            "parent": _production_resolve_parent(self, style, parent_lookup),
            "season": _production_resolve_season(self, header, style),
            "po_number": po_number,
            "dept_number": str(header.get("dept_number", "") or ""),
            "store_number": str(header.get("store_number", "") or ""),
            "po_date": str(header.get("po_date", "") or ""),
            "po_time": str(header.get("po_time", "") or ""),
            "ship_date": str(header.get("ship_date", "") or ""),
            "cancel_date": str(header.get("cancel_date", "") or ""),
            "color": _production_style_color_summary(header, style),
            "size_range": size_range,
            "size_scale": size_scale,
            "order_qty": _production_style_order_qty(header, style),
            "status": str(header.get("status", "") or "draft"),
            "updated_at": str(header.get("updated_at", "") or ""),
        }
    ) or {}


def build_production_rows_from_purchase_orders(self) -> list[dict]:
    source_orders = _production_po_display_source_rows(self)
    _append_production_debug_log(f"build-from-po start po_display_rows={len(source_orders)}")
    saved_rows_by_id = _production_saved_row_map(self)
    saved_shared_by_style_season = _production_saved_shared_fields_by_style_season(list(saved_rows_by_id.values()))
    parent_lookup = _production_cached_style_parent_lookup(self)
    _append_production_debug_log(f"build-from-po parent_lookup={len(parent_lookup)}")
    rows: list[dict] = []
    for line_index, order in enumerate(source_orders, start=1):
        if not isinstance(order, dict):
            continue
        row = _build_production_row_from_po(self, order, line_index, parent_lookup)
        if row:
            merged = _merge_production_saved_fields(row, saved_rows_by_id.get(str(row.get("record_id", "")).strip()))
            shared_values = saved_shared_by_style_season.get(_production_style_season_key(merged))
            if shared_values:
                merged = _apply_production_shared_fields(merged, shared_values)
            rows.append(merged)
    _append_production_debug_log(f"build-from-po done rows={len(rows)}")
    return rows


def refresh_production_module(self) -> None:
    _append_production_debug_log("refresh-module start")
    self.production_rows = self.build_production_rows_from_purchase_orders()
    _append_production_debug_log(f"refresh-module built from purchase_order rows={len(self.production_rows)}")
    for row in self.production_rows:
        row["latest_user"] = self.get_entity_latest_user_display("production", row.get("record_id", "")) if hasattr(self, "get_entity_latest_user_display") else row.get("latest_user", "")
    self.apply_production_filter()
    _append_production_debug_log(
        f"refresh-module done production_rows={len(getattr(self, 'production_rows', []) or [])} "
        f"filtered={len(getattr(self, 'filtered_production_rows', []) or [])}"
    )


def _build_production_module(self, parent: ttk.Frame) -> None:
    _append_production_debug_log("build-ui start")
    parent.columnconfigure(0, weight=1)
    parent.rowconfigure(3, weight=1)

    toolbar = ttk.Frame(parent)
    toolbar.grid(row=0, column=0, sticky="ew")
    self.widget_text["production_edit_button"] = ttk.Button(toolbar, text=self.t("edit"), command=self.edit_selected_production_order)
    self.widget_text["production_edit_button"].pack(side="left")
    self.register_permission_widget("action.production.edit", self.widget_text["production_edit_button"])
    self.widget_text["production_delete_button"] = ttk.Button(toolbar, text=self.t("delete_button"), command=self.delete_selected_production_order)
    self.widget_text["production_delete_button"].pack(side="left", padx=(8, 0))
    self.register_permission_widget("action.production.delete", self.widget_text["production_delete_button"])
    self.widget_text["production_export_button"] = ttk.Button(toolbar, text=self.t("export_report_toolbar"), command=self.export_production_report)
    self.widget_text["production_export_button"].pack(side="left", padx=(8, 0))
    self.register_permission_widget("action.production.export_report", self.widget_text["production_export_button"])
    self.widget_text["production_packing_list_button"] = ttk.Button(toolbar, text=self.t("production_packing_list_button"), command=self.export_selected_production_packing_list)
    self.widget_text["production_packing_list_button"].pack(side="left", padx=(8, 0))
    self.register_permission_widget("action.production.packing_list", self.widget_text["production_packing_list_button"])
    self.widget_text["production_carton_sticker_button"] = ttk.Button(toolbar, text=self.t("production_carton_sticker_button"), command=self.export_selected_production_carton_stickers)
    self.widget_text["production_carton_sticker_button"].pack(side="left", padx=(8, 0))
    self.register_permission_widget("action.production.packing_list", self.widget_text["production_carton_sticker_button"])
    self.widget_text["production_factory_list_button"] = ttk.Button(toolbar, text=self.t("production_factory_list_button"), command=self.open_production_factory_list_window)
    self.widget_text["production_factory_list_button"].pack(side="left", padx=(8, 0))
    self.register_permission_widget("action.production.factory_list", self.widget_text["production_factory_list_button"])
    self.widget_text["production_liquidation_button"] = ttk.Button(toolbar, text=self.t("production_liquidation_button"), command=self.export_selected_production_liquidation)
    self.widget_text["production_liquidation_button"].pack(side="left", padx=(8, 0))
    self.register_permission_widget("action.production.export_report", self.widget_text["production_liquidation_button"])

    meta = ttk.Frame(parent)
    meta.grid(row=1, column=0, sticky="ew", pady=(12, 14))
    meta.columnconfigure(14, weight=1)
    self.production_filter_controls = meta
    self.production_filter_rows = []
    self.widget_text["production_filter_field_label"] = ttk.Label(meta, text=self.t("samples_filter_field_label"))
    self.widget_text["production_filter_field_label"].grid(row=0, column=0, sticky="w", padx=(0, 6))
    self.production_filter_field_combo = ttk.Combobox(meta, textvariable=self.production_filter_field_var, state="readonly", width=24)
    self.production_filter_field_combo.grid(row=0, column=1, sticky="w")
    self.production_filter_field_combo.bind("<<ComboboxSelected>>", self.on_production_filter_field_changed)
    self.widget_text["production_filter_value_label"] = ttk.Label(meta, text=self.t("samples_filter_value_label"))
    self.widget_text["production_filter_value_label"].grid(row=0, column=2, sticky="w", padx=(12, 6))
    self.production_search_entry = ttk.Entry(meta, textvariable=self.production_search_var, width=36)
    self.production_search_entry.grid(row=0, column=3, sticky="w")
    self.production_search_entry.bind("<Return>", self.on_production_search_submit)
    self.production_search_entry.bind("<KP_Enter>", self.on_production_search_submit)
    self.widget_text["production_date_from_label"] = ttk.Label(meta, text=self.t("date_from_label"))
    self.widget_text["production_date_from_label"].grid(row=0, column=4, sticky="w", padx=(12, 6))
    self.production_date_from_entry = ttk.Entry(meta, textvariable=self.production_date_from_var, width=12)
    self.production_date_from_entry.grid(row=0, column=5, sticky="w", padx=(0, 12))
    self.bind_date_entry_picker(self.production_date_from_entry, self.production_date_from_var)
    self.production_date_from_entry.bind("<Return>", self.on_production_search_submit)
    self.production_date_from_entry.bind("<KP_Enter>", self.on_production_search_submit)
    self.widget_text["production_date_to_label"] = ttk.Label(meta, text=self.t("date_to_label"))
    self.widget_text["production_date_to_label"].grid(row=0, column=6, sticky="w", padx=(0, 6))
    self.production_date_to_entry = ttk.Entry(meta, textvariable=self.production_date_to_var, width=12)
    self.production_date_to_entry.grid(row=0, column=7, sticky="w")
    self.bind_date_entry_picker(self.production_date_to_entry, self.production_date_to_var)
    self.production_date_to_entry.bind("<Return>", self.on_production_search_submit)
    self.production_date_to_entry.bind("<KP_Enter>", self.on_production_search_submit)
    self.widget_text["production_sort_by_label"] = ttk.Label(meta, text=self.t("sort_by_label"))
    self.widget_text["production_sort_by_label"].grid(row=0, column=8, sticky="w", padx=(12, 6))
    self.production_sort_key_combo = ttk.Combobox(meta, textvariable=self.production_sort_key_var, state="readonly", width=22)
    self.production_sort_key_combo.grid(row=0, column=9, sticky="w")
    self.production_sort_key_combo.bind("<<ComboboxSelected>>", self.on_production_sort_key_changed)
    self.widget_text["production_sort_order_label"] = ttk.Label(meta, text=self.t("sort_order_label"))
    self.widget_text["production_sort_order_label"].grid(row=0, column=10, sticky="w", padx=(12, 6))
    self.production_sort_order_combo = ttk.Combobox(meta, textvariable=self.production_sort_order_var, state="readonly", width=12)
    self.production_sort_order_combo.grid(row=0, column=11, sticky="w")
    self.production_sort_order_combo.bind("<<ComboboxSelected>>", self.on_production_sort_order_changed)
    self.widget_text["production_add_filter_button"] = ttk.Button(meta, text=self.t("po_add_filter"), command=self.add_production_filter_row)
    self.widget_text["production_add_filter_button"].grid(row=0, column=12, sticky="w", padx=(12, 0))
    self.widget_text["production_clear_filters_button"] = ttk.Button(meta, text=self.t("po_clear_filters"), command=self.clear_production_filters)
    self.widget_text["production_clear_filters_button"].grid(row=0, column=13, sticky="w", padx=(8, 0))

    self.widget_text["production_orders_section"] = ttk.Label(parent, text=self.t("production_orders_section"), style="Section.TLabel")
    self.widget_text["production_orders_section"].grid(row=2, column=0, sticky="nw", pady=(0, 8))

    table_frame = ttk.Frame(parent)
    table_frame.grid(row=3, column=0, sticky="nsew")
    table_frame.columnconfigure(0, weight=1)
    table_frame.rowconfigure(0, weight=1)

    self.production_tree = ttk.Treeview(table_frame, columns=PRODUCTION_COLUMNS, show="tree headings", selectmode="browse", style="Costing.Treeview", height=12)
    self.production_tree.column("#0", width=96, minwidth=96, anchor="center", stretch=False)
    self.production_tree.heading("#0", text=self.t("production_image_column"))
    column_widths = {
        "select_flag": 60,
        "created_at": 125,
        "production_order": 150,
        "factory": 120,
        "mr_pic": 120,
        "buyer": 110,
        "style": 100,
        "parent": 100,
        "season": 95,
        "po_number": 115,
        "po_date": 95,
        "po_time": 80,
        "ship_date": 95,
        "cancel_date": 95,
        "ex_fty_date_plan": 120,
        "actual_ex_fty": 120,
        "color": 100,
        "size_range": 105,
        "size_scale": 105,
        "order_qty": 90,
        "ship_qty": 90,
        "status": 95,
        "over_short_ship_qty": 135,
        "over_short_ship_percent": 135,
        "final_inspection_date": 135,
        "carton_qty": 95,
        "odd_carton_qty": 120,
        "cbm": 80,
        "net_weight": 100,
        "gross_weight": 110,
        "updated_at": 125,
        "latest_user": 140,
    }
    for column_key in PRODUCTION_COLUMNS:
        anchor = "center" if column_key in {"select_flag", "po_date", "po_time", "ship_date", "cancel_date", "ex_fty_date_plan", "actual_ex_fty", "final_inspection_date", "status"} else "w"
        self.production_tree.column(column_key, width=column_widths[column_key], anchor=anchor, stretch=False)
        self.production_tree.heading(
            column_key,
            text=self.production_field_label(column_key),
            command=lambda key=column_key: self.on_production_heading_click(key),
        )
    configure_striped_treeview(self.production_tree)
    scroll_y = ttk.Scrollbar(table_frame, orient="vertical", command=self.production_tree.yview)
    scroll_x = ttk.Scrollbar(table_frame, orient="horizontal", command=self.production_tree.xview)
    self.production_tree.configure(yscrollcommand=scroll_y.set, xscrollcommand=scroll_x.set)
    self.production_tree.grid(row=0, column=0, sticky="nsew")
    scroll_y.grid(row=0, column=1, sticky="ns")
    scroll_x.grid(row=1, column=0, sticky="ew")
    self.production_tree.bind("<Button-1>", self.on_production_tree_click)
    self.production_tree.bind("<Double-1>", self.on_production_double_click)

    self.production_status_label = ttk.Label(
        parent,
        textvariable=self.status_var,
        relief="sunken",
        anchor="w",
        justify="left",
        padding=8,
        wraplength=1180,
    )
    self.production_status_label.grid(row=4, column=0, sticky="ew", pady=(12, 0))
    self.configure_production_filter_options()
    self.update_production_filter_input_state()
    _append_production_debug_log("build-ui done")


def configure_production_filter_options(self) -> None:
    self.production_filter_label_to_key = {self.production_filter_label(key): key for key, _label in PRODUCTION_FILTER_FIELD_OPTIONS}
    self.production_filter_key_to_label = {key: self.production_filter_label(key) for key, _label in PRODUCTION_FILTER_FIELD_OPTIONS}
    self.production_sort_label_to_key = {self.production_sort_label(key): key for key, _label in PRODUCTION_SORT_KEY_OPTIONS}
    self.production_sort_key_to_label = {key: self.production_sort_label(key) for key, _label in PRODUCTION_SORT_KEY_OPTIONS}
    self.production_filter_field_combo.configure(values=[self.production_filter_label(key) for key, _label in PRODUCTION_FILTER_FIELD_OPTIONS])
    self.production_sort_key_combo.configure(values=[self.production_sort_label(key) for key, _label in PRODUCTION_SORT_KEY_OPTIONS])
    self.production_sort_order_combo.configure(values=[self.t(text_key) for _key, text_key in [("asc", "ascending"), ("desc", "descending")]])
    self.production_filter_field_var.set(self.production_filter_key_to_label.get(self.production_filter_field_internal, self.t("samples_filter_all_option")))
    self.production_sort_key_var.set(self.production_sort_key_to_label.get(self.production_sort_key_internal, self.production_field_label("created_at")))
    self.production_sort_order_var.set(self.t("descending") if self.production_sort_order_internal == "desc" else self.t("ascending"))


def update_production_filter_input_state(self, *, clear_irrelevant: bool = False) -> None:
    filter_field = getattr(self, "production_filter_field_internal", "__all__")
    is_date_field = filter_field in PRODUCTION_DATE_FILTER_FIELDS
    if clear_irrelevant:
        if is_date_field:
            self.production_search_var.set("")
            self.production_search_committed_value = ""
        else:
            self.production_date_from_var.set("")
            self.production_date_to_var.set("")
    self.production_search_entry.configure(state="disabled" if is_date_field else "normal")
    self.production_date_from_entry.configure(state="normal" if is_date_field else "disabled")
    self.production_date_to_entry.configure(state="normal" if is_date_field else "disabled")


def apply_production_filter(self) -> None:
    if getattr(self, "_production_filter_update_suspended", False):
        _append_production_debug_log("apply-filter skipped suspended")
        return
    filtered = list(getattr(self, "production_rows", []) or [])
    before_count = len(filtered)
    active_filters = self.get_active_production_filters()
    if active_filters:
        filtered = [row for row in filtered if all(self.production_row_matches_filter(row, item) for item in active_filters)]
    sort_key = self.production_sort_key_internal
    reverse = self.production_sort_order_internal == "desc"

    def sort_value(row: dict) -> object:
        value = row.get(sort_key, "")
        if sort_key in PRODUCTION_DATE_FILTER_FIELDS:
            return self.parse_sort_value(sort_key, str(value or ""))
        if sort_key in PRODUCTION_NUMERIC_SORT_FIELDS:
            return _safe_float_value(value)
        return str(value or "").lower()

    filtered.sort(key=sort_value, reverse=reverse)
    self.filtered_production_rows = filtered
    _append_production_debug_log(
        f"apply-filter rows={before_count} filtered={len(filtered)} filters={active_filters!r} sort={sort_key} reverse={reverse} "
        f"tree_exists={hasattr(self, 'production_tree')}"
    )
    if hasattr(self, "production_tree"):
        self.refresh_production_tree()
    self.update_production_module_status()


def refresh_production_tree(self) -> None:
    _append_production_debug_log(
        f"refresh-tree start rows={len(getattr(self, 'production_rows', []) or [])} "
        f"filtered={len(getattr(self, 'filtered_production_rows', []) or [])}"
    )
    selected_id = self.get_selected_production_record_id()
    self.production_tree.delete(*self.production_tree.get_children())
    self.production_thumbnail_photos = []
    thumbnail_limit = self.get_startup_thumbnail_render_limit("production") if hasattr(self, "get_startup_thumbnail_render_limit") else None
    if thumbnail_limit is None:
        thumbnail_limit = PRODUCTION_TREE_THUMBNAIL_LIMIT
    valid_ids = {str(row.get("record_id", "")).strip() for row in self.production_rows if str(row.get("record_id", "")).strip()}
    self.checked_production_ids.intersection_update(valid_ids)
    inserted_count = 0
    insert_error_count = 0
    visible_rows = list(self.filtered_production_rows[:PRODUCTION_TREE_RENDER_LIMIT])
    for index, row in enumerate(visible_rows, start=1):
        record_id = str(row.get("record_id", "")).strip()
        if not record_id:
            continue
        thumbnail_photo = None
        if thumbnail_limit is None or index <= thumbnail_limit:
            thumbnail_photo = self.create_production_thumbnail(row)
            if thumbnail_photo is not None:
                self.production_thumbnail_photos.append(thumbnail_photo)
        values = []
        for key in PRODUCTION_COLUMNS:
            if key == "select_flag":
                values.append("[x]" if record_id in self.checked_production_ids else "[ ]")
            else:
                values.append(self.display_value(row.get(key)))
        insert_kwargs = {
            "iid": record_id,
            "text": "",
            "values": tuple(values),
            "tags": ("odd_row" if index % 2 == 1 else "even_row",),
        }
        if thumbnail_photo is not None:
            insert_kwargs["image"] = thumbnail_photo
        try:
            self.production_tree.insert("", "end", **insert_kwargs)
            inserted_count += 1
        except Exception as exc:
            insert_error_count += 1
            if insert_error_count <= 5:
                _append_production_debug_log(f"refresh-tree insert failed record_id={record_id} error={exc}")
    if selected_id and self.production_tree.exists(selected_id):
        self.production_tree.selection_set(selected_id)
        self.production_tree.focus(selected_id)
        self.production_tree.see(selected_id)
    if hasattr(self, "note_startup_thumbnail_render_state"):
        self.note_startup_thumbnail_render_state(
            "production",
            total_rows=len(visible_rows),
            rendered_rows=min(len(visible_rows), thumbnail_limit) if thumbnail_limit is not None else len(visible_rows),
        )
    self.update_production_module_status()
    child_count = 0
    try:
        child_count = len(self.production_tree.get_children())
    except Exception:
        pass
    _append_production_debug_log(
        f"refresh-tree done inserted={inserted_count} errors={insert_error_count} tree_children={child_count} "
        f"render_limit={PRODUCTION_TREE_RENDER_LIMIT}"
    )


def create_production_thumbnail(self, row: dict, target_width: int = 84, target_height: int = 84) -> ImageTk.PhotoImage | None:
    image_path = str(row.get("image_path", "") or "").strip()
    if not image_path:
        style = normalize_style_identifier(row.get("style"))
        for source_row in list(getattr(self, "tech_pack_library", []) or []):
            if normalize_style_identifier(source_row.get("style_code")) == style:
                image_path = str(source_row.get("image_path") or source_row.get("preview_image_path") or "").strip()
                break
    if not image_path:
        return None
    try:
        return create_contained_photo(image_path, target_width=target_width, target_height=target_height)
    except Exception:
        return None


def update_production_module_status(self) -> None:
    total = len(getattr(self, "production_rows", []) or [])
    shown = len(getattr(self, "filtered_production_rows", []) or [])
    checked = len(getattr(self, "checked_production_ids", set()) or set())
    order_qty = sum(_safe_float_value(row.get("order_qty")) for row in getattr(self, "filtered_production_rows", []) or [])
    ship_qty = sum(_safe_float_value(row.get("ship_qty")) for row in getattr(self, "filtered_production_rows", []) or [])
    rendered = min(shown, PRODUCTION_TREE_RENDER_LIMIT)
    suffix = f" | Showing first {rendered}" if shown > rendered else ""
    self.set_status(
        f"Production: {shown}/{total} | Export checked: {checked} | Order Qty: {_format_number(order_qty)} | Ship Qty: {_format_number(ship_qty)}{suffix}"
    )
    _append_production_debug_log(f"status total={total} shown={shown} checked={checked}")


def get_selected_production_record_id(self) -> str:
    if not hasattr(self, "production_tree"):
        return ""
    selection = self.production_tree.selection()
    return str(selection[0]).strip() if selection else ""


def get_selected_production_row(self) -> dict | None:
    record_id = self.get_selected_production_record_id()
    if not record_id:
        return None
    for row in getattr(self, "production_rows", []) or []:
        if str(row.get("record_id", "")).strip() == record_id:
            return dict(row)
    return None


def on_production_heading_click(self, key: str) -> None:
    if key == "select_flag":
        visible_ids = [str(row.get("record_id", "")).strip() for row in self.filtered_production_rows if str(row.get("record_id", "")).strip()]
        checked_visible = [record_id for record_id in visible_ids if record_id in self.checked_production_ids]
        if checked_visible and len(checked_visible) == len(visible_ids):
            self.checked_production_ids.difference_update(visible_ids)
        else:
            self.checked_production_ids.update(visible_ids)
        self.update_production_tree_check_cell()
        if visible_ids:
            self.production_tree.selection_set(visible_ids[0])
            self.production_tree.focus(visible_ids[0])
        self.update_production_module_status()
        return
    if self.production_sort_key_internal == key:
        self.production_sort_order_internal = "asc" if self.production_sort_order_internal == "desc" else "desc"
    else:
        self.production_sort_key_internal = key
    self.production_sort_key_var.set(self.production_sort_key_to_label.get(self.production_sort_key_internal, key))
    self.production_sort_order_var.set(self.t("descending") if self.production_sort_order_internal == "desc" else self.t("ascending"))
    self.apply_production_filter()


def update_production_tree_check_cell(self, row_id: str | None = None) -> None:
    target_ids = [row_id] if row_id else list(self.production_tree.get_children())
    for record_id in target_ids:
        if self.production_tree.exists(record_id):
            self.production_tree.set(record_id, "select_flag", "[x]" if record_id in self.checked_production_ids else "[ ]")


def on_production_tree_click(self, event: tk.Event) -> None:
    region = self.production_tree.identify("region", event.x, event.y)
    if region != "cell":
        return
    column_id = self.production_tree.identify_column(event.x)
    try:
        column_index = int(column_id.replace("#", "")) - 1
    except Exception:
        return
    if column_index < 0 or column_index >= len(PRODUCTION_COLUMNS):
        return
    if PRODUCTION_COLUMNS[column_index] != "select_flag":
        return
    row_id = self.production_tree.identify_row(event.y)
    if not row_id:
        return
    if row_id in self.checked_production_ids:
        self.checked_production_ids.remove(row_id)
    else:
        self.checked_production_ids.add(row_id)
        self.production_tree.selection_set(row_id)
        self.production_tree.focus(row_id)
    self.update_production_tree_check_cell(row_id)
    self.update_production_module_status()
    return "break"


def on_production_double_click(self, _event: object | None = None) -> None:
    self.edit_selected_production_order()


def on_production_filter_field_changed(self, _event: object | None = None) -> None:
    label = self.production_filter_field_var.get()
    self.production_filter_field_internal = self.production_filter_label_to_key.get(label, "__all__")
    self._production_filter_update_suspended = True
    try:
        self.update_production_filter_input_state(clear_irrelevant=True)
    finally:
        self._production_filter_update_suspended = False


def on_production_sort_key_changed(self, _event: object | None = None) -> None:
    self.production_sort_key_internal = self.production_sort_label_to_key.get(self.production_sort_key_var.get(), "created_at")
    self.apply_production_filter()


def on_production_sort_order_changed(self, _event: object | None = None) -> None:
    self.production_sort_order_internal = "desc" if self.production_sort_order_var.get() == self.t("descending") else "asc"
    self.apply_production_filter()


def on_production_search_submit(self, _event: object | None = None) -> str:
    self.production_filter_field_committed_internal = getattr(self, "production_filter_field_internal", "__all__")
    self.production_search_committed_value = self.production_search_var.get().strip()
    self.production_date_from_committed_value = self.production_date_from_var.get().strip()
    self.production_date_to_committed_value = self.production_date_to_var.get().strip()
    for row_data in list(getattr(self, "production_filter_rows", []) or []):
        row_data["committed_field_internal"] = str(row_data.get("field_internal", "__all__") or "__all__")
        value_var = row_data.get("value_var")
        from_var = row_data.get("from_var")
        to_var = row_data.get("to_var")
        row_data["committed_query"] = value_var.get().strip() if value_var is not None else ""
        row_data["committed_from"] = from_var.get().strip() if from_var is not None else ""
        row_data["committed_to"] = to_var.get().strip() if to_var is not None else ""
    self.apply_production_filter()
    return "break"


def production_row_matches_filter(self, row: dict, filter_item: dict) -> bool:
    field = str(filter_item.get("field", "__all__") or "__all__")
    query = str(filter_item.get("query", "") or "").strip().lower()
    from_text = str(filter_item.get("from", "") or "").strip()
    to_text = str(filter_item.get("to", "") or "").strip()
    if field in PRODUCTION_DATE_FILTER_FIELDS and (from_text or to_text):
        return self.is_within_date_range(row.get(field), from_text, to_text)
    if not query:
        return True
    if field == "__all__":
        return query in " ".join(
            [self.display_value(row.get("image_path"))]
            + [self.display_value(row.get(key)) for key in PRODUCTION_COLUMNS if key != "select_flag"]
        ).lower()
    return query in self.display_value(row.get(field)).strip().lower()


def get_active_production_filters(self) -> list[dict]:
    active: list[dict] = []
    field = str(getattr(self, "production_filter_field_committed_internal", getattr(self, "production_filter_field_internal", "__all__")) or "__all__")
    query = str(getattr(self, "production_search_committed_value", "") or "").strip()
    from_text = str(getattr(self, "production_date_from_committed_value", "") or "").strip()
    to_text = str(getattr(self, "production_date_to_committed_value", "") or "").strip()
    if field in PRODUCTION_DATE_FILTER_FIELDS:
        if from_text or to_text:
            active.append({"field": field, "from": from_text, "to": to_text})
    elif query:
        active.append({"field": field, "query": query})
    for row_data in list(getattr(self, "production_filter_rows", []) or []):
        row_field = str(row_data.get("committed_field_internal", row_data.get("field_internal", "__all__")) or "__all__")
        row_query = str(row_data.get("committed_query", "") or "").strip()
        row_from = str(row_data.get("committed_from", "") or "").strip()
        row_to = str(row_data.get("committed_to", "") or "").strip()
        if row_field in PRODUCTION_DATE_FILTER_FIELDS:
            if row_from or row_to:
                active.append({"field": row_field, "from": row_from, "to": row_to})
        elif row_query:
            active.append({"field": row_field, "query": row_query})
    return active


def add_production_filter_row(self) -> None:
    rows = getattr(self, "production_filter_rows", [])
    row_data = create_extra_filter_row(
        self,
        module_key="production",
        parent=self.production_filter_controls,
        options=PRODUCTION_FILTER_FIELD_OPTIONS,
        date_fields=PRODUCTION_DATE_FILTER_FIELDS,
        row_index=len(rows) + 1,
        remove_command=self.remove_production_filter_row,
        submit_command=self.on_production_search_submit,
        translate_filter_field=self.production_filter_label,
        option_label_getter=lambda key, _label: self.production_filter_label(key),
    )
    rows.append(row_data)
    self.production_filter_rows = rows


def remove_production_filter_row(self, row_data: dict) -> None:
    rows = [row for row in list(getattr(self, "production_filter_rows", []) or []) if row is not row_data]
    destroy_filter_row(row_data)
    self.production_filter_rows = rows
    regrid_filter_rows(rows)
    self.apply_production_filter()


def clear_production_filters(self) -> None:
    self._production_filter_update_suspended = True
    try:
        self.production_filter_field_internal = "__all__"
        self.production_filter_field_committed_internal = "__all__"
        self.production_filter_field_var.set(self.production_filter_label("__all__"))
        self.production_search_var.set("")
        self.production_search_committed_value = ""
        self.production_date_from_committed_value = ""
        self.production_date_to_committed_value = ""
        self.production_date_from_var.set("")
        self.production_date_to_var.set("")
        for row_data in list(getattr(self, "production_filter_rows", []) or []):
            destroy_filter_row(row_data)
        self.production_filter_rows = []
    finally:
        self._production_filter_update_suspended = False
    self.update_production_filter_input_state()
    self.apply_production_filter()


def edit_selected_production_order(self) -> None:
    row = self.get_selected_production_row()
    if not isinstance(row, dict):
        messagebox.showwarning(self.t("warning_title"), "Please select one Production Order first.")
        return
    self.open_production_order_detail_window(row)


def delete_selected_production_order(self) -> None:
    target_ids = set(self.checked_production_ids)
    selected_id = self.get_selected_production_record_id()
    if not target_ids and selected_id:
        target_ids.add(selected_id)
    if not target_ids:
        messagebox.showwarning(self.t("warning_title"), "Please select at least one Production Order first.")
        return
    if not messagebox.askyesno(self.t("warning_title"), f"Delete {len(target_ids)} selected Production Order row(s)?"):
        return
    remaining = [row for row in self.production_rows if str(row.get("record_id", "")).strip() not in target_ids]
    self.delete_production_detail_rows_from_source(target_ids)
    self.production_rows = remaining
    self.checked_production_ids.difference_update(target_ids)
    self.apply_production_filter()


def _selected_production_rows_for_packing(self) -> list[dict]:
    checked_ids = set(getattr(self, "checked_production_ids", set()) or set())
    visible_rows = list(getattr(self, "filtered_production_rows", []) or [])
    if checked_ids:
        rows = [dict(row) for row in visible_rows if str(row.get("record_id", "")).strip() in checked_ids]
        existing_ids = {str(row.get("record_id", "")).strip() for row in rows}
        rows.extend(
            dict(row)
            for row in list(getattr(self, "production_rows", []) or [])
            if str(row.get("record_id", "")).strip() in checked_ids and str(row.get("record_id", "")).strip() not in existing_ids
        )
        return rows
    selected_row = self.get_selected_production_row()
    return [dict(selected_row)] if isinstance(selected_row, dict) else []


def load_production_packing_list_assets_from_source(self) -> dict[str, object]:
    default_value = default_production_packing_list_assets()
    if self.should_use_server_data_source():
        if self.is_local_data_mode():
            self.ensure_local_server_running()
        try:
            payload = fetch_app_setting(self.server_settings, PRODUCTION_PACKING_LIST_ASSETS_KEY, default_value)
            merged = dict(default_value)
            if isinstance(payload, dict):
                merged.update(payload)
            return merged
        except Exception:
            pass
    payload = get_app_setting(DB_PATH, PRODUCTION_PACKING_LIST_ASSETS_KEY, default_value)
    merged = dict(default_value)
    if isinstance(payload, dict):
        merged.update(payload)
    return merged


def save_production_packing_list_assets_to_source(self, payload: dict[str, object]) -> dict[str, object]:
    normalized = dict(default_production_packing_list_assets())
    normalized.update(payload if isinstance(payload, dict) else {})
    if self.should_use_server_data_source():
        if self.is_local_data_mode():
            self.ensure_local_server_running()
        saved = save_app_setting(self.server_settings, PRODUCTION_PACKING_LIST_ASSETS_KEY, normalized)
        return dict(saved) if isinstance(saved, dict) else normalized
    saved = set_app_setting(DB_PATH, PRODUCTION_PACKING_LIST_ASSETS_KEY, normalized)
    return dict(saved) if isinstance(saved, dict) else normalized


def load_production_carton_sticker_assets_from_source(self) -> dict[str, object]:
    default_value = default_production_carton_sticker_assets()
    if self.should_use_server_data_source():
        if self.is_local_data_mode():
            self.ensure_local_server_running()
        try:
            payload = fetch_app_setting(self.server_settings, PRODUCTION_CARTON_STICKER_ASSETS_KEY, default_value)
            merged = dict(default_value)
            if isinstance(payload, dict):
                merged.update(payload)
            return merged
        except Exception:
            pass
    payload = get_app_setting(DB_PATH, PRODUCTION_CARTON_STICKER_ASSETS_KEY, default_value)
    merged = dict(default_value)
    if isinstance(payload, dict):
        merged.update(payload)
    return merged


def save_production_carton_sticker_assets_to_source(self, payload: dict[str, object]) -> dict[str, object]:
    normalized = dict(default_production_carton_sticker_assets())
    normalized.update(payload if isinstance(payload, dict) else {})
    if self.should_use_server_data_source():
        if self.is_local_data_mode():
            self.ensure_local_server_running()
        saved = save_app_setting(self.server_settings, PRODUCTION_CARTON_STICKER_ASSETS_KEY, normalized)
        return dict(saved) if isinstance(saved, dict) else normalized
    saved = set_app_setting(DB_PATH, PRODUCTION_CARTON_STICKER_ASSETS_KEY, normalized)
    return dict(saved) if isinstance(saved, dict) else normalized


def resolve_production_packing_list_template_asset(self, value: str, *, fallback_suffix: str = ".xlsx") -> Path | None:
    raw_value = str(value or "").strip()
    if not raw_value:
        return None
    candidate = Path(raw_value)
    if candidate.exists() and candidate.is_file():
        return candidate
    if raw_value.lower().startswith(("http://", "https://")):
        try:
            split = urlsplit(raw_value)
            normalized_url = urlunsplit(
                (
                    split.scheme,
                    split.netloc,
                    quote(split.path, safe="/:@"),
                    quote(split.query, safe="=&?/:@"),
                    quote(split.fragment, safe="=&?/:@"),
                )
            )
            parsed = urlparse(normalized_url)
            suffix = Path(parsed.path).suffix or fallback_suffix
            cache_dir = DATA_DIR / ("carton_sticker_assets" if fallback_suffix == ".carton-sticker.xlsx" else "packing_list_assets")
            cache_dir.mkdir(parents=True, exist_ok=True)
            target_path = cache_dir / f"{hashlib.sha1(raw_value.encode('utf-8')).hexdigest()}{suffix}"
            if target_path.exists() and target_path.is_file():
                return target_path
            request = Request(normalized_url, headers={"User-Agent": "CitiFoxERPApp/desktop"})
            with open_url(request, timeout=20) as response:
                target_path.write_bytes(response.read())
            return target_path if target_path.exists() else None
        except Exception:
            return None
    return None


def ensure_production_packing_list_template_asset(self) -> Path:
    assets = self.load_production_packing_list_assets_from_source()
    template_url = str(assets.get("template_url", "") or "").strip()
    template_path = self.resolve_production_packing_list_template_asset(template_url)
    if template_path is not None:
        return template_path
    for candidate in (PRODUCTION_PACKING_LIST_TEMPLATE_PATH, PRODUCTION_PACKING_LIST_TEMPLATE_FALLBACK_PATH):
        candidate_path = Path(str(candidate or "").strip())
        if candidate_path.exists() and candidate_path.is_file():
            return candidate_path
    raise FileNotFoundError(f"Packing List template was not found. Expected: {PRODUCTION_PACKING_LIST_TEMPLATE_PATH}")


def _safe_production_sheet_title(raw_title: object, used_titles: set[str]) -> str:
    title = str(raw_title or "").strip() or "Packing List"
    for char in r'[]:*?/\\':
        title = title.replace(char, "-")
    title = " ".join(title.split())[:31].strip() or "Packing List"
    base = title
    counter = 2
    while title in used_titles:
        suffix = f" {counter}"
        title = f"{base[:31 - len(suffix)]}{suffix}".strip()
        counter += 1
    used_titles.add(title)
    return title


def _production_excel_carton_dimension(value: object) -> str:
    text = str(value or "").strip()
    if not text:
        return ""
    lower_text = text.lower().replace("(cm)", "").replace("cm", "")
    parts = [part.strip() for part in lower_text.replace("*", "x").split("x") if part.strip()]
    if len(parts) >= 3:
        return "*".join(parts[:3])
    return text


def _production_carton_cbm_formula(row_index: int, carton_column: str, dimension: object) -> str:
    dimension_text = _production_excel_carton_dimension(dimension)
    parts: list[float] = []
    for raw_part in dimension_text.split("*"):
        value = _safe_float_value(raw_part)
        if value > 0:
            parts.append(value / 100)
    if len(parts) != 3:
        return ""
    return f"={carton_column}{row_index}*{parts[0]}*{parts[1]}*{parts[2]}"


def _production_carton_cbm_value(cartons: float, dimension: object) -> float:
    dimension_text = _production_excel_carton_dimension(dimension)
    parts: list[float] = []
    for raw_part in dimension_text.split("*"):
        value = _safe_float_value(raw_part)
        if value > 0:
            parts.append(value / 100)
    if len(parts) != 3 or cartons <= 0:
        return 0.0
    return cartons * parts[0] * parts[1] * parts[2]


def _copy_production_cell_style(source_cell, target_cell) -> None:
    if source_cell.has_style:
        target_cell.font = copy(source_cell.font)
        target_cell.fill = copy(source_cell.fill)
        target_cell.border = copy(source_cell.border)
        target_cell.alignment = copy(source_cell.alignment)
        target_cell.number_format = source_cell.number_format
        target_cell.protection = copy(source_cell.protection)


def _production_packing_size_label(self, value: object) -> str:
    if hasattr(self, "normalize_size_code"):
        size_code = self.normalize_size_code(value)
    else:
        size_code = str(value or "").strip().upper().replace(" ", "")
    petite_map = {
        "PETXS": "PXS",
        "PETSM": "PS",
        "PETS": "PS",
        "PETMD": "PM",
        "PETM": "PM",
        "PETLG": "PL",
        "PETL": "PL",
        "PETXL": "PXL",
    }
    return petite_map.get(size_code, size_code)


PRODUCTION_SIZE_SYSTEM_ORDER = {
    "petite": ["PXS", "PS", "PM", "PL", "PXL"],
    "missy": ["XS", "S", "M", "L", "XL"],
    "women": ["1X", "2X", "3X"],
}


def _production_size_system_for_labels(size_labels: list[str]) -> str:
    normalized = {str(size or "").strip().upper() for size in size_labels if str(size or "").strip()}
    for system_key, ordered_sizes in PRODUCTION_SIZE_SYSTEM_ORDER.items():
        if normalized and normalized.issubset(set(ordered_sizes)):
            return system_key
    if any(size.startswith("P") for size in normalized):
        return "petite"
    if any(size.endswith("X") and size[:1].isdigit() for size in normalized):
        return "women"
    return "missy"


def _production_order_sizes_for_system(size_labels: list[str]) -> list[str]:
    system_key = _production_size_system_for_labels(size_labels)
    ordered_sizes = PRODUCTION_SIZE_SYSTEM_ORDER.get(system_key, PRODUCTION_SIZE_SYSTEM_ORDER["missy"])
    existing = {str(size or "").strip().upper() for size in size_labels if str(size or "").strip()}
    extras = sorted(size for size in existing if size not in set(ordered_sizes))
    ordered = [size for size in ordered_sizes if size in existing]
    return ordered + extras


def _production_ordered_size_labels(self, items: list[dict]) -> list[str]:
    raw_sizes = [str(item.get("size_desc", "") or "").strip() for item in items if str(item.get("size_desc", "") or "").strip()]
    if not raw_sizes:
        return []
    if hasattr(self, "sort_size_codes"):
        raw_sizes = list(self.sort_size_codes(raw_sizes))
    ordered: list[str] = []
    seen: set[str] = set()
    for raw_size in raw_sizes:
        size_code = _production_packing_size_label(self, raw_size)
        if size_code and size_code not in seen:
            seen.add(size_code)
            ordered.append(size_code)
    return _production_order_sizes_for_system(ordered)


def _production_size_breakdown(self, row: dict) -> tuple[list[str], dict[str, float], dict[str, float]]:
    items = self.get_production_po_detail_line_items(row)
    return _production_size_breakdown_from_items(self, items)


def _production_size_breakdown_from_items(self, items: list[dict]) -> tuple[list[str], dict[str, float], dict[str, float]]:
    size_labels = _production_ordered_size_labels(self, items)
    pack_qty_by_size = {size: 0.0 for size in size_labels}
    order_qty_by_size = {size: 0.0 for size in size_labels}
    for item in items:
        size = _production_packing_size_label(self, item.get("size_desc"))
        if not size:
            continue
        if size not in pack_qty_by_size:
            size_labels.append(size)
            pack_qty_by_size[size] = 0.0
            order_qty_by_size[size] = 0.0
        pack_qty_by_size[size] += _safe_float_value(item.get("pack_qty"))
        order_qty_by_size[size] += _safe_float_value(item.get("total_units"))
    ordered_labels = _production_order_sizes_for_system(size_labels)
    return ordered_labels, pack_qty_by_size, order_qty_by_size


def _allocate_production_quantity_by_size(total_qty: float, basis_by_size: dict[str, float], size_labels: list[str]) -> dict[str, float]:
    total_qty_int = int(round(total_qty))
    basis_total = sum(max(0.0, basis_by_size.get(size, 0.0)) for size in size_labels)
    if total_qty_int <= 0 or basis_total <= 0:
        return {size: 0.0 for size in size_labels}
    allocations: dict[str, float] = {}
    fractions: list[tuple[float, str]] = []
    assigned = 0
    for size in size_labels:
        exact = total_qty_int * max(0.0, basis_by_size.get(size, 0.0)) / basis_total
        whole = int(exact)
        allocations[size] = float(whole)
        assigned += whole
        fractions.append((exact - whole, size))
    for _fraction, size in sorted(fractions, reverse=True)[: max(0, total_qty_int - assigned)]:
        allocations[size] += 1.0
    return allocations


def _prepare_production_packing_sheet_columns(sheet, size_count: int) -> tuple[int, int, int, int, int, int]:
    display_size_count = max(3, size_count)
    if display_size_count > 3:
        extra_columns = display_size_count - 3
        sheet.insert_cols(13, extra_columns)
        for column_index in range(13, 13 + extra_columns):
            source_column = column_index - 1
            sheet.column_dimensions[get_column_letter(column_index)].width = sheet.column_dimensions[get_column_letter(source_column)].width
            for row_index in range(1, 40):
                _copy_production_cell_style(sheet.cell(row=row_index, column=source_column), sheet.cell(row=row_index, column=column_index))
    unit_col = 10 + display_size_count
    qty_per_ctn_col = unit_col + 1
    total_qty_col = unit_col + 2
    box_col = unit_col + 3
    cbm_col = unit_col + 4
    remark_col = unit_col + 5
    return unit_col, qty_per_ctn_col, total_qty_col, box_col, cbm_col, remark_col


def _fill_production_packing_sheet(self, sheet, row: dict) -> None:
    working_row = dict(row)
    _recalculate_production_packing(working_row)
    color_items = working_row.get("_packing_color_items")
    if isinstance(color_items, list):
        size_labels, pack_qty_by_size, order_qty_by_size = _production_size_breakdown_from_items(self, [dict(item) for item in color_items if isinstance(item, dict)])
    else:
        size_labels, pack_qty_by_size, order_qty_by_size = _production_size_breakdown(self, working_row)
    if not size_labels:
        size_labels = [str(working_row.get("size_range", "") or "").strip() or "SIZE"]
        pack_qty_by_size = {size_labels[0]: _safe_float_value(self.production_unit_per_pack(working_row))}
        order_qty_by_size = {size_labels[0]: _safe_float_value(working_row.get("order_qty"))}

    unit_col, qty_per_ctn_col, total_qty_col, box_col, cbm_col, remark_col = _prepare_production_packing_sheet_columns(sheet, len(size_labels))
    total_qty_letter = get_column_letter(total_qty_col)
    cbm_letter = get_column_letter(cbm_col)

    sheet["R2"] = datetime.now()
    sheet["R2"].number_format = "m/d/yyyy"
    for index, size in enumerate(size_labels, start=10):
        sheet.cell(row=4, column=index).value = size
        sheet.cell(row=13, column=index).value = size
    for index in range(10 + len(size_labels), 10 + max(3, len(size_labels))):
        sheet.cell(row=4, column=index).value = ""
        sheet.cell(row=13, column=index).value = ""

    style = str(working_row.get("style", "") or "").strip()
    po_number = str(working_row.get("po_number", "") or "").strip()
    store = str(working_row.get("store_number", "") or "").strip()
    dept = str(working_row.get("dept_number", "") or "").strip()
    color = str(working_row.get("_packing_color_label") or working_row.get("color", "") or "").strip()
    unit_per_pack = sum(pack_qty_by_size.get(size, 0.0) for size in size_labels)
    unit_per_carton = _safe_float_value(working_row.get("unit_per_carton"))
    ship_qty = _safe_float_value(working_row.get("ship_qty"))
    order_qty = _safe_float_value(working_row.get("order_qty")) or sum(order_qty_by_size.get(size, 0.0) for size in size_labels)
    carton_qty = int(_safe_float_value(working_row.get("carton_qty")))
    odd_qty = _safe_float_value(working_row.get("odd_carton_qty"))

    packing_total_cartons = 0.0
    packing_total_qty = 0.0
    packing_total_cbm = 0.0

    def fill_carton_row(row_index: int, carton_from: int | str, cartons: float, total_units: float, box_dimension: str, ppk_qty: float) -> None:
        nonlocal packing_total_cartons, packing_total_qty, packing_total_cbm
        sheet.cell(row=row_index, column=1).value = carton_from
        sheet.cell(row=row_index, column=2).value = f"=A{row_index}+C{row_index}-1" if carton_from and cartons else ""
        sheet.cell(row=row_index, column=3).value = _excel_number(cartons) if cartons else ""
        sheet.cell(row=row_index, column=4).value = _excel_number(ppk_qty) if ppk_qty else ""
        sheet.cell(row=row_index, column=5).value = style
        sheet.cell(row=row_index, column=6).value = po_number
        sheet.cell(row=row_index, column=7).value = store
        sheet.cell(row=row_index, column=8).value = dept
        sheet.cell(row=row_index, column=9).value = color
        for offset, size in enumerate(size_labels):
            sheet.cell(row=row_index, column=10 + offset).value = _excel_number(pack_qty_by_size.get(size, 0.0))
        sheet.cell(row=row_index, column=unit_col).value = _excel_number(unit_per_pack)
        sheet.cell(row=row_index, column=qty_per_ctn_col).value = _excel_number(total_units / cartons) if cartons else ""
        sheet.cell(row=row_index, column=total_qty_col).value = _excel_number(total_units)
        sheet.cell(row=row_index, column=box_col).value = box_dimension
        cbm_value = _production_carton_cbm_value(cartons, box_dimension)
        sheet.cell(row=row_index, column=cbm_col).value = _excel_number(cbm_value) if cbm_value else ""
        packing_total_cartons += cartons
        packing_total_qty += total_units
        packing_total_cbm += cbm_value

    for row_index in (5, 6, 7):
        for column_index in range(1, remark_col + 1):
            sheet.cell(row=row_index, column=column_index).value = None

    next_carton = 1
    wrote_main_row = False
    if carton_qty > 0 and unit_per_carton > 0:
        fill_carton_row(
            5,
            next_carton,
            carton_qty,
            carton_qty * unit_per_carton,
            _production_excel_carton_dimension(working_row.get("carton_dimension")),
            unit_per_carton / unit_per_pack if unit_per_pack else 0,
        )
        wrote_main_row = True
        next_carton += carton_qty
    if not wrote_main_row:
        fill_carton_row(
            5,
            "",
            0,
            ship_qty or order_qty,
            _production_excel_carton_dimension(working_row.get("carton_dimension")),
            0,
        )
    if odd_qty > 0:
        fill_carton_row(
            6,
            next_carton,
            1,
            odd_qty,
            _production_excel_carton_dimension(working_row.get("odd_carton_dimension")),
            odd_qty / unit_per_pack if unit_per_pack else 0,
        )

    sheet.cell(row=8, column=3).value = _excel_number(packing_total_cartons) if packing_total_cartons else 0
    sheet.cell(row=8, column=total_qty_col).value = _excel_number(packing_total_qty) if packing_total_qty else 0
    sheet.cell(row=8, column=cbm_col).value = _excel_number(packing_total_cbm) if packing_total_cbm else 0

    shipped_by_size = _allocate_production_quantity_by_size(ship_qty, order_qty_by_size, size_labels)
    total_ship_qty = sum(shipped_by_size.get(size, 0.0) for size in size_labels)
    total_order_qty = sum(order_qty_by_size.get(size, 0.0) for size in size_labels)
    total_over_short_qty = total_ship_qty - total_order_qty
    total_over_short_percent = total_over_short_qty / total_order_qty if total_order_qty else 0
    for offset, size in enumerate(size_labels):
        column_index = 10 + offset
        shipped_size_qty = shipped_by_size.get(size, 0.0)
        order_size_qty = order_qty_by_size.get(size, 0.0)
        over_short_size_qty = shipped_size_qty - order_size_qty
        sheet.cell(row=14, column=column_index).value = _excel_number(shipped_size_qty)
        sheet.cell(row=15, column=column_index).value = _excel_number(order_size_qty)
        sheet.cell(row=16, column=column_index).value = _excel_number(over_short_size_qty)
        sheet.cell(row=17, column=column_index).value = over_short_size_qty / order_size_qty if order_size_qty else 0
        sheet.cell(row=17, column=column_index).number_format = "0.00%"
    summary_values = {
        14: total_ship_qty,
        15: total_order_qty,
        16: total_over_short_qty,
        17: total_over_short_percent,
        18: total_ship_qty,
        19: total_order_qty,
        20: total_over_short_qty,
        21: total_over_short_percent,
    }
    for row_index, value in summary_values.items():
        sheet.cell(row=row_index, column=unit_col).value = value if row_index in (17, 21) else _excel_number(value)
        if row_index in (17, 21):
            sheet.cell(row=row_index, column=unit_col).number_format = "0.00%"
    sheet.cell(row=23, column=10).value = _excel_number(packing_total_cartons) if packing_total_cartons else 0
    sheet.cell(row=24, column=10).value = _excel_number(packing_total_qty) if packing_total_qty else 0
    if str(working_row.get("net_weight", "") or "").strip():
        sheet.cell(row=24, column=unit_col).value = working_row.get("net_weight")
    if str(working_row.get("gross_weight", "") or "").strip():
        sheet.cell(row=24, column=unit_col + 1).value = working_row.get("gross_weight")


def export_selected_production_packing_list(self) -> None:
    rows = _selected_production_rows_for_packing(self)
    if not rows:
        messagebox.showwarning(self.t("warning_title"), "Please select at least one Production Order row first.")
        return
    try:
        template_path = self.ensure_production_packing_list_template_asset()
    except Exception as exc:
        messagebox.showwarning(
            self.t("warning_title"),
            f"Packing List template was not found.\n\n{exc}",
        )
        return
    target_path = filedialog.asksaveasfilename(
        title="Export Packing List",
        defaultextension=".xlsx",
        filetypes=[("Excel Workbook", "*.xlsx")],
        initialfile=f"packing_list_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
    )
    if not target_path:
        return
    try:
        template_workbook = load_workbook(template_path)
        template_sheet = template_workbook.worksheets[0]
        workbook = Workbook()
        workbook.remove(workbook.active)
        used_titles: set[str] = set()
        created_sheets = []
        for production_row in rows:
            color_summaries = _production_color_summaries(self, production_row)
            if not color_summaries:
                color_summaries = [
                    {
                        "color_label": str(production_row.get("color", "") or "No Color"),
                        "items": self.get_production_po_detail_line_items(production_row),
                        "ship_qty": str(production_row.get("ship_qty", "") or ""),
                    }
                ]
            for color_summary in color_summaries:
                color_label = str(color_summary.get("color_label", "") or "No Color")
                color_row = dict(production_row)
                color_row["color"] = color_label
                color_row["ship_qty"] = str(color_summary.get("ship_qty", "") or production_row.get("ship_qty", "") or "")
                color_row["_packing_color_label"] = color_label
                color_row["_packing_color_items"] = list(color_summary.get("items", []) or [])
                _recalculate_production_packing(color_row)
                sheet = workbook.create_sheet(
                    title=_safe_production_sheet_title(
                        f"{production_row.get('style', '')} {production_row.get('po_number', '')} {color_label}",
                        used_titles,
                    )
                )
                _copy_production_template_sheet_layout(template_sheet, sheet)
                _fill_production_packing_sheet(self, sheet, color_row)
                created_sheets.append(sheet)
        workbook.active = 0
        try:
            workbook.calculation.calcMode = "auto"
            workbook.calculation.fullCalcOnLoad = True
            workbook.calculation.forceFullCalc = True
        except Exception:
            pass
        workbook.save(target_path)
    except Exception as exc:
        messagebox.showerror(self.t("error_title"), f"Could not export Packing List:\n{exc}")
        return
    self.set_status(f"Exported Packing List: {target_path}")
    messagebox.showinfo("Packing List", f"Exported {len(created_sheets)} sheet(s).")


def ensure_production_liquidation_template_asset(self) -> Path:
    for candidate in (PRODUCTION_LIQUIDATION_TEMPLATE_PATH, PRODUCTION_LIQUIDATION_TEMPLATE_FALLBACK_PATH):
        candidate_path = Path(str(candidate or "").strip())
        if candidate_path.exists() and candidate_path.is_file():
            return candidate_path
    raise FileNotFoundError(f"Liquidation template was not found. Expected: {PRODUCTION_LIQUIDATION_TEMPLATE_PATH}")


def _production_liquidation_material_sort_key(row: dict) -> tuple[int, str, str]:
    type_text = str(row.get("type", "") or "").strip().lower()
    section_text = str(row.get("section", "") or "").strip().lower()
    item_text = str(row.get("item_name", "") or "").strip().lower()
    is_fabric = type_text == "fabric" or section_text in {"shell", "fabric", "mesh", "knit", "woven"} or "fabric" in item_text
    return (0 if is_fabric else 1, section_text, item_text)


def _production_liquidation_booking_consumption_by_line(self, style: object) -> dict[str, str]:
    versions = _production_consumption_versions_for_style(self, style)
    booking_version = next(
        (
            dict(version)
            for version in versions
            if str(version.get("version_type", "") or version.get("version_id", "")).strip().lower() == "booking"
        ),
        {},
    )
    lookup: dict[str, str] = {}
    for line in list(booking_version.get("lines", []) or []):
        if not isinstance(line, dict):
            continue
        consumption = str(line.get("consumption", "") or "").strip()
        for key in (
            str(line.get("line_id", "") or "").strip(),
            str(line.get("bom_item_id", "") or "").strip(),
            str(line.get("bom_item_code", "") or line.get("item_code", "") or "").strip(),
        ):
            if key and key not in lookup:
                lookup[key] = consumption
    return lookup


def _production_liquidation_booking_consumption(material_row: dict, booking_lookup: dict[str, str]) -> str:
    for key in (
        str(material_row.get("line_id", "") or "").strip(),
        str(material_row.get("item_id", "") or "").strip(),
        str(material_row.get("item_code", "") or "").strip(),
    ):
        if key and key in booking_lookup:
            return booking_lookup[key]
    return ""


def _production_liquidation_number(value: object) -> int | float | str:
    text = str(value or "").strip()
    if not text or text == "-":
        return ""
    number = _safe_float_value(text)
    if number == 0 and not re.search(r"\d", text):
        return text
    return _excel_number(number)


def _fill_production_liquidation_sheet(self, sheet, row: dict) -> int:
    style = normalize_style_identifier(row.get("style"))
    sheet["E4"] = style
    sheet["G4"] = str(row.get("mr_pic", "") or "").strip()
    sheet["O4"] = str(row.get("actual_ex_fty", "") or "").strip()
    sheet["U4"] = str(row.get("factory", "") or "").strip()
    for cell_address in ("E4", "G4", "U4"):
        sheet[cell_address].number_format = "General"

    material_rows = self.build_production_material_rows_from_consumption(row) if hasattr(self, "build_production_material_rows_from_consumption") else []
    material_rows = sorted([dict(item) for item in material_rows if isinstance(item, dict)], key=_production_liquidation_material_sort_key)
    booking_lookup = _production_liquidation_booking_consumption_by_line(self, style)
    order_qty = _production_liquidation_number(row.get("order_qty"))
    ship_qty = _production_liquidation_number(row.get("ship_qty"))
    actual_cut_qty = _production_liquidation_number(row.get("actual_cut_qty"))

    for row_index in range(7, 15):
        for column_letter in ("A", "B", "D", "E", "F", "G", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "V", "W", "X", "Y", "Z", "AA", "AB"):
            sheet[f"{column_letter}{row_index}"] = ""

    for offset, material_row in enumerate(material_rows[:8]):
        row_index = 7 + offset
        booking_consumption = _production_liquidation_booking_consumption(material_row, booking_lookup)
        production_consumption = str(material_row.get("consumption", "") or "").strip()
        sheet[f"A{row_index}"] = style
        sheet[f"B{row_index}"] = str(material_row.get("item_name", "") or material_row.get("item_code", "") or "").strip()
        sheet[f"D{row_index}"] = str(material_row.get("color", "") or "").strip()
        sheet[f"E{row_index}"] = order_qty
        sheet[f"F{row_index}"] = _production_liquidation_number(booking_consumption)
        sheet[f"G{row_index}"] = _production_liquidation_number(production_consumption)
        sheet[f"J{row_index}"] = _production_liquidation_number(material_row.get("fabric_weight"))
        sheet[f"K{row_index}"] = _production_liquidation_number(material_row.get("required_qty"))
        sheet[f"L{row_index}"] = f"=K{row_index}/F{row_index}/1.03"
        sheet[f"M{row_index}"] = actual_cut_qty
        sheet[f"N{row_index}"] = f"=L{row_index}-M{row_index}"
        sheet[f"O{row_index}"] = ship_qty
        sheet[f"P{row_index}"] = f"=M{row_index}-O{row_index}"
        sheet[f"Q{row_index}"] = f"=K{row_index}-(M{row_index}*G{row_index}*1.03)"
        sheet[f"S{row_index}"] = f"=SUM(Q{row_index}:Q{row_index})-R{row_index}"
        sheet[f"V{row_index}"] = f"=E{row_index}*F{row_index}*1.03"
        sheet[f"W{row_index}"] = f"=Y{row_index}+Z{row_index}+AA{row_index}+AB{row_index}"
        sheet[f"X{row_index}"] = f"=W{row_index}-V{row_index}"
    return max(0, len(material_rows) - 8)


def export_selected_production_liquidation(self) -> None:
    rows = _selected_production_rows_for_packing(self)
    if not rows:
        messagebox.showwarning(self.t("warning_title"), "Please select at least one Production Order row first.")
        return
    try:
        template_path = self.ensure_production_liquidation_template_asset()
    except Exception as exc:
        messagebox.showwarning(self.t("warning_title"), f"Liquidation template was not found.\n\n{exc}")
        return
    target_path = filedialog.asksaveasfilename(
        title="Export Liquidation",
        defaultextension=".xlsx",
        filetypes=[("Excel Workbook", "*.xlsx")],
        initialfile=f"liquidation_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
    )
    if not target_path:
        return
    skipped_material_rows = 0
    try:
        template_workbook = load_workbook(template_path)
        template_sheet = template_workbook.worksheets[0]
        workbook = Workbook()
        workbook.remove(workbook.active)
        used_titles: set[str] = set()
        created_sheets = []
        for production_row in rows:
            sheet = workbook.create_sheet(
                title=_safe_production_sheet_title(
                    f"Liquidation {production_row.get('style', '')} {production_row.get('po_number', '')}",
                    used_titles,
                )
            )
            _copy_production_template_sheet_layout(template_sheet, sheet)
            skipped_material_rows += _fill_production_liquidation_sheet(self, sheet, production_row)
            created_sheets.append(sheet)
        workbook.active = 0
        try:
            workbook.calculation.calcMode = "auto"
            workbook.calculation.fullCalcOnLoad = True
            workbook.calculation.forceFullCalc = True
        except Exception:
            pass
        workbook.save(target_path)
    except Exception as exc:
        messagebox.showerror(self.t("error_title"), f"Could not export Liquidation:\n{exc}")
        return
    self.set_status(f"Exported Liquidation: {target_path}")
    message = f"Exported {len(created_sheets)} Liquidation sheet(s)."
    if skipped_material_rows:
        message += f"\n\n{skipped_material_rows} material row(s) exceeded template rows 7-14 and were not exported."
    messagebox.showinfo("Liquidation", message)


def ensure_production_carton_sticker_template_asset(self) -> Path:
    assets = self.load_production_carton_sticker_assets_from_source()
    template_url = str(assets.get("template_url", "") or "").strip()
    template_path = self.resolve_production_packing_list_template_asset(template_url, fallback_suffix=".carton-sticker.xlsx")
    if template_path is not None:
        return template_path
    for candidate in (PRODUCTION_CARTON_STICKER_TEMPLATE_PATH, PRODUCTION_CARTON_STICKER_TEMPLATE_FALLBACK_PATH):
        candidate_path = Path(str(candidate or "").strip())
        if candidate_path.exists() and candidate_path.is_file():
            return candidate_path
    raise FileNotFoundError(f"Carton sticker template was not found. Expected: {PRODUCTION_CARTON_STICKER_TEMPLATE_PATH}")


def _normalize_production_store_code(value: object) -> str:
    digits = "".join(ch for ch in str(value or "").strip() if ch.isdigit())
    return digits.lstrip("0") or digits


def _production_store_template_sheet(workbook, store_value: object):
    target_store = _normalize_production_store_code(store_value)
    if not target_store:
        return None
    for sheet in workbook.worksheets:
        title = str(sheet.title or "").strip()
        if not title.upper().startswith("STORE"):
            continue
        if _normalize_production_store_code(title) == target_store:
            return sheet
    return None


def _production_carton_sticker_sheet_title(row: dict, color_label: str, used_titles: set[str]) -> str:
    return _safe_production_sheet_title(
        f"Store {row.get('store_number', '')} {row.get('po_number', '')} {row.get('style', '')} {color_label}",
        used_titles,
    )


def _production_carton_sticker_pack_text(unit_per_carton: float, unit_per_pack: float) -> str:
    carton_units = _format_number(unit_per_carton) if unit_per_carton else ""
    pack_units = _format_number(unit_per_pack) if unit_per_pack else ""
    pack_count = _format_number(unit_per_carton / unit_per_pack) if unit_per_carton and unit_per_pack else ""
    if carton_units and pack_units and pack_count:
        return f"Master carton: {carton_units}pcs\nInner packs: {pack_units}pcs/{pack_count}ppk"
    if carton_units:
        return f"Master carton: {carton_units}pcs"
    return "Master carton:"


def _fill_production_carton_sticker_sheet(self, sheet, row: dict, color_summary: dict[str, object]) -> None:
    color_label = str(color_summary.get("color_label", "") or row.get("color", "") or "").strip()
    items = [dict(item) for item in list(color_summary.get("items", []) or []) if isinstance(item, dict)]
    size_labels, pack_qty_by_size, order_qty_by_size = _production_size_breakdown_from_items(self, items)
    if not size_labels:
        size_labels = [
            item.strip()
            for item in str(row.get("size_range", "") or "").replace("/", "-").split("-")
            if item.strip()
        ]
    if not size_labels:
        size_labels = ["SIZE"]
        pack_qty_by_size = {"SIZE": _safe_float_value(self.production_unit_per_pack(row))}
        order_qty_by_size = {"SIZE": _safe_float_value(row.get("order_qty"))}

    working_row = dict(row)
    working_row["color"] = color_label
    working_row["ship_qty"] = str(color_summary.get("ship_qty", "") or row.get("ship_qty", "") or "")
    _recalculate_production_packing(working_row)

    po_number = str(working_row.get("po_number", "") or "").strip()
    sheet["A3"] = f"PO#: {po_number}\nCOLOR: {color_label}\nSize:"
    sheet["A9"] = "=A3"

    visible_sizes = size_labels[:4]
    for offset in range(4):
        column_index = 1 + offset
        size = visible_sizes[offset] if offset < len(visible_sizes) else ""
        sheet.cell(row=4, column=column_index).value = size
        sheet.cell(row=5, column=column_index).value = _excel_number(pack_qty_by_size.get(size, 0.0)) if size else ""
        sheet.cell(row=10, column=column_index).value = size
    unit_per_pack = sum(_safe_float_value(pack_qty_by_size.get(size, 0.0)) for size in size_labels)
    if unit_per_pack <= 0:
        unit_per_pack = _safe_float_value(self.production_unit_per_pack(working_row))
    unit_per_carton = _safe_float_value(working_row.get("unit_per_carton"))
    carton_qty = _safe_float_value(working_row.get("carton_qty"))
    odd_qty = _safe_float_value(working_row.get("odd_carton_qty"))
    sheet["E5"] = _excel_number(carton_qty) if carton_qty else ""
    sheet["A6"] = _production_carton_sticker_pack_text(unit_per_carton, unit_per_pack)

    if odd_qty > 0:
        for offset, size in enumerate(visible_sizes):
            sheet.cell(row=11, column=1 + offset).value = _excel_number(pack_qty_by_size.get(size, 0.0))
        sheet["E11"] = 1
        sheet["A12"] = _production_carton_sticker_pack_text(odd_qty, unit_per_pack)
    else:
        for offset in range(4):
            sheet.cell(row=11, column=1 + offset).value = ""
        sheet["E11"] = ""
        sheet["A12"] = ""


def _copy_production_template_column_dimensions(source_sheet, target_sheet) -> None:
    max_column = max(source_sheet.max_column or 1, 1)
    for source_dimension in source_sheet.column_dimensions.values():
        min_column = max(int(source_dimension.min or 1), 1)
        max_source_column = min(int(source_dimension.max or min_column), max_column)
        if min_column > max_column:
            continue
        for column_index in range(min_column, max_source_column + 1):
            target_dimension = target_sheet.column_dimensions[get_column_letter(column_index)]
            target_dimension.width = source_dimension.width
            target_dimension.hidden = source_dimension.hidden
            target_dimension.bestFit = source_dimension.bestFit
            target_dimension.outlineLevel = source_dimension.outlineLevel
            target_dimension.collapsed = source_dimension.collapsed


def _copy_production_template_row_dimensions(source_sheet, target_sheet) -> None:
    for row_index, source_dimension in source_sheet.row_dimensions.items():
        target_dimension = target_sheet.row_dimensions[row_index]
        target_dimension.height = source_dimension.height
        target_dimension.hidden = source_dimension.hidden
        target_dimension.outlineLevel = source_dimension.outlineLevel
        target_dimension.collapsed = source_dimension.collapsed


def _copy_production_template_page_setup(source_sheet, target_sheet) -> None:
    source_page_setup = source_sheet.page_setup
    target_page_setup = target_sheet.page_setup
    for attr_name in (
        "orientation",
        "paperSize",
        "scale",
        "fitToWidth",
        "fitToHeight",
        "firstPageNumber",
        "useFirstPageNumber",
        "paperHeight",
        "paperWidth",
        "pageOrder",
        "usePrinterDefaults",
        "blackAndWhite",
        "draft",
        "cellComments",
        "errors",
        "horizontalDpi",
        "verticalDpi",
        "copies",
    ):
        attr_value = getattr(source_page_setup, attr_name, None)
        if attr_value is not None:
            setattr(target_page_setup, attr_name, attr_value)


def _copy_production_template_sheet_layout(source_sheet, target_sheet) -> None:
    target_sheet.sheet_properties = copy(source_sheet.sheet_properties)
    target_sheet.sheet_format = copy(source_sheet.sheet_format)
    target_sheet.page_margins = copy(source_sheet.page_margins)
    target_sheet.print_options = copy(source_sheet.print_options)
    target_sheet.freeze_panes = source_sheet.freeze_panes
    target_sheet.sheet_view.showGridLines = source_sheet.sheet_view.showGridLines
    target_sheet.sheet_view.zoomScale = source_sheet.sheet_view.zoomScale
    target_sheet.sheet_view.zoomScaleNormal = source_sheet.sheet_view.zoomScaleNormal
    target_sheet.sheet_view.view = "normal"

    _copy_production_template_page_setup(source_sheet, target_sheet)

    _copy_production_template_column_dimensions(source_sheet, target_sheet)
    _copy_production_template_row_dimensions(source_sheet, target_sheet)

    for row in source_sheet.iter_rows(
        min_row=1,
        max_row=source_sheet.max_row,
        min_col=1,
        max_col=source_sheet.max_column,
    ):
        for source_cell in row:
            target_cell = target_sheet[source_cell.coordinate]
            target_cell.value = source_cell.value
            _copy_production_cell_style(source_cell, target_cell)
            if source_cell.hyperlink:
                target_cell._hyperlink = copy(source_cell.hyperlink)
            if source_cell.comment:
                target_cell.comment = copy(source_cell.comment)

    for merged_range in source_sheet.merged_cells.ranges:
        target_sheet.merge_cells(str(merged_range))


def export_selected_production_carton_stickers(self) -> None:
    rows = _selected_production_rows_for_packing(self)
    if not rows:
        messagebox.showwarning(self.t("warning_title"), "Please select at least one Production Order row first.")
        return
    try:
        template_path = self.ensure_production_carton_sticker_template_asset()
    except Exception as exc:
        messagebox.showwarning(
            self.t("warning_title"),
            f"Carton sticker template was not found.\n\n{exc}",
        )
        return
    target_path = filedialog.asksaveasfilename(
        title="Export Carton Sticker",
        defaultextension=".xlsx",
        filetypes=[("Excel Workbook", "*.xlsx")],
        initialfile=f"carton_sticker_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
    )
    if not target_path:
        return
    try:
        template_workbook = load_workbook(template_path)
        workbook = Workbook()
        workbook.remove(workbook.active)
        used_titles: set[str] = set()
        created_sheets = []
        missing_stores: set[str] = set()
        for production_row in rows:
            template_sheet = _production_store_template_sheet(template_workbook, production_row.get("store_number"))
            if template_sheet is None:
                missing_stores.add(str(production_row.get("store_number", "") or "-").strip() or "-")
                continue
            color_summaries = _production_color_summaries(self, production_row)
            if not color_summaries:
                color_summaries = [
                    {
                        "color_label": str(production_row.get("color", "") or "No Color"),
                        "items": self.get_production_po_detail_line_items(production_row),
                        "ship_qty": str(production_row.get("ship_qty", "") or ""),
                    }
                ]
            for color_summary in color_summaries:
                color_label = str(color_summary.get("color_label", "") or "No Color")
                sheet = workbook.create_sheet(
                    title=_production_carton_sticker_sheet_title(production_row, color_label, used_titles)
                )
                _copy_production_template_sheet_layout(template_sheet, sheet)
                _fill_production_carton_sticker_sheet(self, sheet, production_row, color_summary)
                created_sheets.append(sheet)
        if not created_sheets:
            missing_text = ", ".join(sorted(missing_stores)) if missing_stores else "-"
            raise ValueError(f"No carton sticker sheet was created. Missing store template(s): {missing_text}")
        workbook.active = 0
        try:
            workbook.calculation.calcMode = "auto"
            workbook.calculation.fullCalcOnLoad = True
            workbook.calculation.forceFullCalc = True
        except Exception:
            pass
        workbook.save(target_path)
    except Exception as exc:
        messagebox.showerror(self.t("error_title"), f"Could not export Carton Sticker:\n{exc}")
        return
    self.set_status(f"Exported Carton Sticker: {target_path}")
    message = f"Exported {len(created_sheets)} carton sticker sheet(s)."
    if missing_stores:
        message += "\n\nMissing store template(s): " + ", ".join(sorted(missing_stores))
    messagebox.showinfo("Carton Sticker", message)


def get_selected_production_factory_id(self) -> str:
    tree = getattr(self, "production_factory_tree", None)
    if tree is None:
        return ""
    selection = tree.selection()
    return str(selection[0]).strip() if selection else ""


def get_selected_production_factory_row(self) -> dict | None:
    factory_id = self.get_selected_production_factory_id()
    if not factory_id:
        return None
    for row in getattr(self, "production_factory_rows", []) or []:
        if str(row.get("factory_id", "")).strip() == factory_id:
            return dict(row)
    return None


def refresh_production_factory_tree(self) -> None:
    tree = getattr(self, "production_factory_tree", None)
    if tree is None:
        return
    selected_id = self.get_selected_production_factory_id()
    tree.delete(*tree.get_children())
    for index, row in enumerate(getattr(self, "filtered_production_factory_rows", []) or [], start=1):
        factory_id = str(row.get("factory_id", "")).strip()
        if not factory_id:
            continue
        values = tuple(self.display_value(row.get(key)) for key in PRODUCTION_FACTORY_COLUMNS)
        tree.insert("", "end", iid=factory_id, values=values, tags=("odd_row" if index % 2 == 1 else "even_row",))
    if selected_id and tree.exists(selected_id):
        tree.selection_set(selected_id)
        tree.focus(selected_id)
    self.on_production_factory_row_selected()
    status_var = getattr(self, "production_factory_status_var", None)
    if isinstance(status_var, tk.StringVar):
        status_var.set(
            f"Factories: {len(getattr(self, 'filtered_production_factory_rows', []) or [])}/"
            f"{len(getattr(self, 'production_factory_rows', []) or [])}"
        )


def apply_production_factory_filter(self) -> None:
    query = str(getattr(self, "production_factory_search_committed_value", getattr(self, "production_factory_search_var", tk.StringVar(value="")).get()) or "").strip().lower()
    rows = list(getattr(self, "production_factory_rows", []) or [])
    if query:
        filtered: list[dict] = []
        for row in rows:
            haystack = " ".join(
                self.display_value(row.get(key))
                for key in (
                    "factory_code",
                    "factory_name",
                    "short_name",
                    "contact_person",
                    "phone",
                    "email",
                    "country",
                    "city",
                    "status",
                )
            ).lower()
            if query in haystack:
                filtered.append(row)
        rows = filtered
    rows.sort(key=lambda item: (str(item.get("factory_name", "")).lower(), str(item.get("factory_code", "")).lower()))
    self.filtered_production_factory_rows = rows
    self.refresh_production_factory_tree()


def refresh_production_factory_list_window(self) -> None:
    self.production_factory_rows = [row for row in self.load_production_factory_rows_from_source() if isinstance(row, dict)]
    self.apply_production_factory_filter()


def on_production_factory_search_submit(self, _event: object | None = None) -> str:
    self.production_factory_search_committed_value = self.production_factory_search_var.get().strip()
    self.apply_production_factory_filter()
    return "break"


def open_production_factory_detail_window(self, row: dict | None = None) -> None:
    is_new = row is None
    source_row = deepcopy(row) if isinstance(row, dict) else default_production_factory_payload()
    dialog = tk.Toplevel(self.root)
    dialog.title("New Factory" if is_new else "Edit Factory")
    dialog.resizable(True, True)
    dialog.geometry("920x600")
    dialog.minsize(820, 520)

    frame = ttk.Frame(dialog, padding=16)
    frame.pack(fill="both", expand=True)
    frame.columnconfigure(0, weight=1)
    frame.rowconfigure(1, weight=1)
    ttk.Label(frame, text=dialog.title(), style="Section.TLabel").grid(row=0, column=0, sticky="w")

    content = ttk.Frame(frame)
    content.grid(row=1, column=0, sticky="nsew", pady=(12, 0))
    content.columnconfigure(0, weight=1)
    content.columnconfigure(1, weight=1)
    content.rowconfigure(6, weight=1)
    vars_map = {key: tk.StringVar(value=str(source_row.get(key, "") or "").strip()) for key in default_production_factory_payload()}
    note_text: tk.Text | None = None

    def add_labeled_entry(row_index: int, column_index: int, label: str, key: str) -> None:
        host = ttk.Frame(content)
        host.grid(row=row_index, column=column_index, sticky="ew", padx=8, pady=(0, 12))
        host.columnconfigure(0, weight=1)
        ttk.Label(host, text=label).grid(row=0, column=0, sticky="w", pady=(0, 4))
        ttk.Entry(host, textvariable=vars_map[key]).grid(row=1, column=0, sticky="ew")

    def add_labeled_combo(row_index: int, column_index: int, label: str, key: str, values: list[str]) -> None:
        host = ttk.Frame(content)
        host.grid(row=row_index, column=column_index, sticky="ew", padx=8, pady=(0, 12))
        host.columnconfigure(0, weight=1)
        ttk.Label(host, text=label).grid(row=0, column=0, sticky="w", pady=(0, 4))
        ttk.Combobox(host, textvariable=vars_map[key], values=values, state="readonly").grid(row=1, column=0, sticky="ew")

    add_labeled_entry(0, 0, "Factory Code", "factory_code")
    add_labeled_entry(0, 1, "Factory Name", "factory_name")
    add_labeled_entry(1, 0, "Short Name", "short_name")
    add_labeled_combo(1, 1, "Status", "status", PRODUCTION_FACTORY_STATUS_OPTIONS)
    add_labeled_entry(2, 0, "Contact Person", "contact_person")
    add_labeled_entry(2, 1, "Phone", "phone")
    add_labeled_entry(3, 0, "Email", "email")
    add_labeled_entry(3, 1, "Capacity / Month", "capacity_month")
    add_labeled_entry(4, 0, "Country", "country")
    add_labeled_entry(4, 1, "City", "city")
    add_labeled_entry(5, 0, "Address", "address_line")

    note_host = ttk.Frame(content)
    note_host.grid(row=6, column=0, columnspan=2, sticky="nsew", padx=8, pady=(0, 12))
    note_host.columnconfigure(0, weight=1)
    note_host.rowconfigure(1, weight=1)
    ttk.Label(note_host, text="Note").grid(row=0, column=0, sticky="w", pady=(0, 4))
    note_text = tk.Text(note_host, height=7, wrap="word", font=("Segoe UI", 10))
    note_text.grid(row=1, column=0, sticky="nsew")
    if str(source_row.get("note", "") or "").strip():
        note_text.insert("1.0", str(source_row.get("note", "") or "").strip())

    actions = ttk.Frame(frame)
    actions.grid(row=2, column=0, sticky="e", pady=(12, 0))

    def save_action() -> None:
        payload = default_production_factory_payload()
        for key in payload:
            payload[key] = vars_map[key].get().strip()
        payload["note"] = note_text.get("1.0", "end-1c").strip() if note_text is not None else ""
        if not payload["factory_code"]:
            messagebox.showwarning(self.t("warning_title"), "Factory Code is required.")
            return
        if not payload["factory_name"]:
            messagebox.showwarning(self.t("warning_title"), "Factory Name is required.")
            return
        existing = normalize_production_factory_row(source_row) or default_production_factory_payload()
        payload["factory_id"] = payload["factory_id"] or str(existing.get("factory_id", "")).strip() or secrets.token_hex(16)
        payload["created_at"] = str(existing.get("created_at", "")).strip() or _production_now_text()
        payload["updated_at"] = _production_now_text()
        saved = self.save_production_factory_row_to_source(payload)
        if not saved:
            messagebox.showerror(self.t("warning_title"), "Could not save factory.")
            return
        self.refresh_production_factory_list_window()
        saved_id = str(saved.get("factory_id", "")).strip()
        if hasattr(self, "production_factory_tree") and saved_id and self.production_factory_tree.exists(saved_id):
            self.production_factory_tree.selection_set(saved_id)
            self.production_factory_tree.focus(saved_id)
        self.set_status(f"Saved factory {saved.get('factory_code', '')}.")
        dialog.destroy()

    ttk.Button(actions, text=self.t("close"), command=dialog.destroy).pack(side="right")
    ttk.Button(actions, text="Save", command=save_action).pack(side="right", padx=(0, 8))


def open_new_production_factory_dialog(self) -> None:
    self.open_production_factory_detail_window(None)


def edit_selected_production_factory_row(self) -> None:
    row = self.get_selected_production_factory_row()
    if row is None:
        messagebox.showwarning(self.t("warning_title"), "Please select one factory first.")
        return
    self.open_production_factory_detail_window(row)


def delete_selected_production_factory_row(self) -> None:
    row = self.get_selected_production_factory_row()
    if row is None:
        messagebox.showwarning(self.t("warning_title"), "Please select one factory first.")
        return
    factory_name = str(row.get("factory_name", "") or row.get("factory_code", "") or "").strip()
    if not messagebox.askyesno(self.t("warning_title"), f"Delete factory '{factory_name}'?"):
        return
    self.delete_production_factory_row_from_source(str(row.get("factory_id", "")).strip())
    self.refresh_production_factory_list_window()
    self.set_status(f"Deleted factory {factory_name}.")


def on_production_factory_row_selected(self, _event: object | None = None) -> None:
    preview_vars = getattr(self, "production_factory_preview_vars", None)
    if not isinstance(preview_vars, dict):
        return
    row = self.get_selected_production_factory_row()
    for key, variable in preview_vars.items():
        if isinstance(variable, tk.StringVar):
            variable.set(self.display_value(row.get(key)) if isinstance(row, dict) else "")


def on_production_factory_row_double_click(self, _event: object | None = None) -> None:
    self.edit_selected_production_factory_row()


def open_production_factory_list_window(self) -> None:
    if not self.is_action_allowed("action.production.factory_list"):
        return
    existing = getattr(self, "production_factory_list_window", None)
    if existing is not None:
        try:
            if existing.winfo_exists():
                existing.deiconify()
                existing.lift()
                existing.focus_force()
                self.refresh_production_factory_list_window()
                return
        except Exception:
            pass

    dialog = tk.Toplevel(self.root)
    dialog.title("Factory List")
    dialog.resizable(True, True)
    dialog.geometry("1120x700")
    dialog.minsize(980, 620)
    self.production_factory_list_window = dialog
    dialog.protocol("WM_DELETE_WINDOW", lambda: close_production_factory_list_window(self))

    frame = ttk.Frame(dialog, padding=16)
    frame.pack(fill="both", expand=True)
    frame.columnconfigure(0, weight=1)
    frame.rowconfigure(3, weight=1)
    ttk.Label(frame, text="Factory List", style="Section.TLabel").grid(row=0, column=0, sticky="w")

    toolbar = ttk.Frame(frame)
    toolbar.grid(row=1, column=0, sticky="ew", pady=(12, 0))
    ttk.Button(toolbar, text="Add", command=self.open_new_production_factory_dialog).pack(side="left")
    ttk.Button(toolbar, text="Edit", command=self.edit_selected_production_factory_row).pack(side="left", padx=(8, 0))
    ttk.Button(toolbar, text="Delete", command=self.delete_selected_production_factory_row).pack(side="left", padx=(8, 0))

    filter_row = ttk.Frame(frame)
    filter_row.grid(row=2, column=0, sticky="ew", pady=(12, 8))
    filter_row.columnconfigure(1, weight=1)
    ttk.Label(filter_row, text="Search").grid(row=0, column=0, sticky="w", padx=(0, 6))
    self.production_factory_search_var = tk.StringVar(value="")
    search_entry = ttk.Entry(filter_row, textvariable=self.production_factory_search_var, width=42)
    search_entry.grid(row=0, column=1, sticky="ew")
    search_entry.bind("<Return>", self.on_production_factory_search_submit)
    search_entry.bind("<KP_Enter>", self.on_production_factory_search_submit)

    table_frame = ttk.Frame(frame)
    table_frame.grid(row=3, column=0, sticky="nsew")
    table_frame.columnconfigure(0, weight=1)
    table_frame.rowconfigure(0, weight=1)
    self.production_factory_tree = ttk.Treeview(
        table_frame,
        columns=PRODUCTION_FACTORY_COLUMNS,
        show="headings",
        selectmode="browse",
        style="Costing.Treeview",
        height=14,
    )
    labels = {
        "factory_code": "Factory Code",
        "factory_name": "Factory Name",
        "contact_person": "Contact Person",
        "phone": "Phone",
        "email": "Email",
        "country": "Country",
        "status": self.t("status"),
        "updated_at": self.t("revised_time_column"),
    }
    widths = {
        "factory_code": 120,
        "factory_name": 240,
        "contact_person": 150,
        "phone": 140,
        "email": 220,
        "country": 120,
        "status": 100,
        "updated_at": 140,
    }
    for column_key in PRODUCTION_FACTORY_COLUMNS:
        self.production_factory_tree.column(column_key, width=widths.get(column_key, 120), anchor="w", stretch=column_key in {"factory_name", "email"})
        self.production_factory_tree.heading(column_key, text=labels.get(column_key, column_key))
    configure_striped_treeview(self.production_factory_tree)
    scroll_y = ttk.Scrollbar(table_frame, orient="vertical", command=self.production_factory_tree.yview)
    scroll_x = ttk.Scrollbar(table_frame, orient="horizontal", command=self.production_factory_tree.xview)
    self.production_factory_tree.configure(yscrollcommand=scroll_y.set, xscrollcommand=scroll_x.set)
    self.production_factory_tree.grid(row=0, column=0, sticky="nsew")
    scroll_y.grid(row=0, column=1, sticky="ns")
    scroll_x.grid(row=1, column=0, sticky="ew")
    self.production_factory_tree.bind("<<TreeviewSelect>>", self.on_production_factory_row_selected)
    self.production_factory_tree.bind("<Double-1>", self.on_production_factory_row_double_click)

    preview = ttk.LabelFrame(frame, text="Basic Information", padding=12)
    preview.grid(row=4, column=0, sticky="ew", pady=(12, 0))
    for column_index in range(4):
        preview.columnconfigure(column_index, weight=1)
    self.production_factory_preview_vars = {
        key: tk.StringVar(value="")
        for key in ("factory_code", "factory_name", "short_name", "status", "contact_person", "phone", "email", "country", "city", "capacity_month", "address_line", "note")
    }

    def add_preview(row_index: int, column_index: int, label: str, key: str, *, columnspan: int = 1) -> None:
        host = ttk.Frame(preview)
        host.grid(row=row_index, column=column_index, columnspan=columnspan, sticky="ew", padx=8, pady=(0, 10))
        host.columnconfigure(0, weight=1)
        ttk.Label(host, text=label).grid(row=0, column=0, sticky="w", pady=(0, 2))
        ttk.Label(host, textvariable=self.production_factory_preview_vars[key], relief="sunken", anchor="w").grid(row=1, column=0, sticky="ew")

    add_preview(0, 0, "Factory Code", "factory_code")
    add_preview(0, 1, "Factory Name", "factory_name", columnspan=2)
    add_preview(0, 3, "Status", "status")
    add_preview(1, 0, "Short Name", "short_name")
    add_preview(1, 1, "Contact Person", "contact_person")
    add_preview(1, 2, "Phone", "phone")
    add_preview(1, 3, "Email", "email")
    add_preview(2, 0, "Country", "country")
    add_preview(2, 1, "City", "city")
    add_preview(2, 2, "Capacity / Month", "capacity_month")
    add_preview(2, 3, "Address", "address_line")
    add_preview(3, 0, "Note", "note", columnspan=4)

    self.production_factory_status_var = tk.StringVar(value="")
    ttk.Label(frame, textvariable=self.production_factory_status_var, relief="sunken", anchor="w", padding=8).grid(row=5, column=0, sticky="ew", pady=(12, 0))

    self.refresh_production_factory_list_window()
    self.apply_permission_state()
    self.center_dialog(dialog, min_width=1120, min_height=700)
    search_entry.focus_set()


def close_production_factory_list_window(self) -> None:
    dialog = getattr(self, "production_factory_list_window", None)
    if dialog is None:
        return
    try:
        dialog.destroy()
    except Exception:
        pass
    self.production_factory_list_window = None


def export_production_report(self) -> None:
    rows = [
        row for row in getattr(self, "filtered_production_rows", []) or []
        if not self.checked_production_ids or str(row.get("record_id", "")).strip() in self.checked_production_ids
    ]
    if not rows:
        messagebox.showwarning(self.t("warning_title"), "There are no Production rows to export.")
        return
    target_path = filedialog.asksaveasfilename(
        title="Export Production Report",
        defaultextension=".xlsx",
        filetypes=[("Excel Workbook", "*.xlsx")],
        initialfile=f"production_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
    )
    if not target_path:
        return
    workbook = Workbook()
    sheet = workbook.active
    sheet.title = "Production"
    headers = ["Image"] + [PRODUCTION_FIELD_LABELS.get(key, key) for key in PRODUCTION_COLUMNS]
    sheet.append(headers)
    for row in rows:
        sheet.append([row.get("image_path", "")] + [row.get(key, "") for key in PRODUCTION_COLUMNS])
    for index, header in enumerate(headers, start=1):
        sheet.column_dimensions[sheet.cell(row=1, column=index).column_letter].width = min(max(len(str(header)) + 2, 12), 28)
    workbook.save(target_path)
    self.set_status(f"Exported Production report: {target_path}")


def open_production_order_detail_window(self, row: dict) -> None:
    dialog = tk.Toplevel(self.root)
    dialog.title(f"Production Order Detail - {row.get('production_order', '')}")
    dialog.resizable(True, True)
    dialog.minsize(1180, 760)
    dialog.columnconfigure(0, weight=1)
    dialog.rowconfigure(1, weight=1)

    header = ttk.Frame(dialog, padding=(14, 12))
    header.grid(row=0, column=0, sticky="ew")
    header.columnconfigure(0, weight=1)
    ttk.Label(header, text=str(row.get("production_order", "") or "Production Order"), style="Section.TLabel").grid(row=0, column=0, sticky="w")
    ttk.Label(header, text=f"{row.get('style', '')} | {row.get('po_number', '')} | {row.get('status', '')}", foreground="#5f6b7a").grid(row=1, column=0, sticky="w", pady=(4, 0))

    notebook = ttk.Notebook(dialog)
    notebook.grid(row=1, column=0, sticky="nsew", padx=14, pady=(0, 12))
    tabs = [
        ("overview", "Overview"),
        ("po_quantity", "PO & Quantity"),
        ("ex_factory", "Ex-Factory"),
        ("cutting", "Cutting"),
        ("packing", "Packing"),
        ("inspection", "Inspection"),
        ("materials", "Materials"),
        ("history_notes", "History / Notes"),
    ]
    field_vars: dict[str, tk.StringVar] = {}
    for tab_key, tab_title in tabs:
        frame = ttk.Frame(notebook, padding=14)
        frame.columnconfigure(0, weight=1)
        frame.columnconfigure(1, weight=1)
        notebook.add(frame, text=tab_title)
        if tab_key == "overview":
            _build_production_detail_fields(self, frame, row, field_vars, ["production_order", "factory", "mr_pic", "buyer", "style", "season", "po_number", "dept_number", "store_number", "color", "status"])
        elif tab_key == "po_quantity":
            _build_production_detail_fields(self, frame, row, field_vars, ["po_date", "po_time", "ship_date", "cancel_date"])
            _build_production_po_line_items_section(self, frame, row, field_vars, start_row=4)
        elif tab_key == "ex_factory":
            _build_production_detail_fields(self, frame, row, field_vars, ["ex_fty_date_plan", "actual_ex_fty"])
        elif tab_key == "cutting":
            _build_production_cutting_section(self, frame, row, field_vars)
        elif tab_key == "packing":
            _build_production_detail_fields(self, frame, row, field_vars, ["unit_per_carton", "carton_dimension", "carton_qty", "odd_carton_qty", "odd_carton_dimension", "cbm", "net_weight", "gross_weight"])
        elif tab_key == "inspection":
            _build_production_detail_fields(self, frame, row, field_vars, ["final_inspection_date"])
        elif tab_key == "materials":
            _build_production_materials_section(self, frame, row, field_vars)
        elif tab_key == "history_notes":
            _build_production_detail_fields(self, frame, row, field_vars, ["created_at", "updated_at", "latest_user"])
            ttk.Label(frame, text="Notes").grid(row=4, column=0, sticky="w", pady=(12, 4))
            notes = tk.Text(frame, height=8, wrap="word")
            notes.grid(row=5, column=0, columnspan=2, sticky="nsew")
            notes.insert("1.0", str(row.get("notes", "") or ""))
            field_vars["notes::__text_widget"] = notes

    _setup_production_packing_calculation(field_vars)

    actions = ttk.Frame(dialog, padding=(14, 0, 14, 14))
    actions.grid(row=2, column=0, sticky="ew")
    actions.columnconfigure(0, weight=1)
    ttk.Button(actions, text="Save", command=lambda: self.save_production_detail_window(row, field_vars, dialog)).grid(row=0, column=1, sticky="e", padx=(0, 8))
    ttk.Button(actions, text="Close", command=lambda: self.close_production_detail_window(dialog)).grid(row=0, column=2, sticky="e")

    self.restore_production_detail_window_state(dialog)
    dialog.protocol("WM_DELETE_WINDOW", lambda: self.close_production_detail_window(dialog))


def restore_production_detail_window_state(self, dialog: tk.Toplevel) -> None:
    geometry = str(getattr(self, "ui_state", {}).get("production_detail_window_geometry", "") or "").strip()
    if geometry:
        try:
            dialog.geometry(geometry)
            return
        except Exception:
            pass
    if hasattr(self, "center_dialog"):
        self.center_dialog(dialog, min_width=1180, min_height=760)


def capture_production_detail_window_state(self, dialog: tk.Toplevel) -> None:
    try:
        if not dialog.winfo_exists():
            return
        dialog.update_idletasks()
        geometry = dialog.winfo_geometry()
    except Exception:
        return
    if not geometry:
        return
    try:
        self.ui_state["production_detail_window_geometry"] = geometry
        if hasattr(self, "persist_ui_state"):
            self.persist_ui_state()
    except Exception:
        pass


def close_production_detail_window(self, dialog: tk.Toplevel) -> None:
    self.capture_production_detail_window_state(dialog)
    try:
        dialog.destroy()
    except Exception:
        pass


def _build_production_cutting_section(self, parent: ttk.Frame, row: dict, field_vars: dict[str, tk.StringVar]) -> None:
    parent.columnconfigure(0, weight=1)
    parent.columnconfigure(1, weight=1)

    ttk.Label(parent, text=self.production_field_label("actual_cut_qty")).grid(row=0, column=0, sticky="w", padx=(0, 12), pady=(0, 4))
    actual_cut_qty_var = tk.StringVar(value=str(row.get("actual_cut_qty", "") or ""))
    field_vars["actual_cut_qty"] = actual_cut_qty_var
    ttk.Entry(parent, textvariable=actual_cut_qty_var).grid(row=1, column=0, sticky="ew", padx=(0, 12), pady=(0, 8))


def _build_production_detail_fields(self, parent: ttk.Frame, row: dict, field_vars: dict[str, tk.StringVar], fields: list[str]) -> None:
    for index, key in enumerate(fields):
        row_index = index // 2 * 2
        column_index = index % 2
        ttk.Label(parent, text=self.production_field_label(key)).grid(row=row_index, column=column_index, sticky="w", padx=(0, 12), pady=(0, 4))
        var = tk.StringVar(value=str(row.get(key, "") or ""))
        field_vars[key] = var
        if key in PRODUCTION_DATE_FILTER_FIELDS:
            entry = ttk.Entry(parent, textvariable=var)
            entry.grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))
            self.bind_date_entry_picker(entry, var)
        elif key == "factory":
            values = self.get_active_production_factory_names() if hasattr(self, "get_active_production_factory_names") else []
            combo = ttk.Combobox(parent, textvariable=var, values=values, state="readonly")
            combo.grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))
        elif key == "status":
            combo = ttk.Combobox(parent, textvariable=var, values=PRODUCTION_STATUS_OPTIONS, state="readonly")
            combo.grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))
        elif key == "fabric_weight_uom":
            if not var.get().strip():
                var.set("KG")
            combo = ttk.Combobox(parent, textvariable=var, values=PRODUCTION_FABRIC_WEIGHT_UOM_OPTIONS, state="readonly")
            combo.grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))
        elif key == "carton_dimension":
            combo = ttk.Combobox(parent, textvariable=var, values=PRODUCTION_CARTON_DIMENSION_OPTIONS, state="readonly")
            combo.grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))
        elif key in {"carton_qty", "odd_carton_qty", "odd_carton_dimension"}:
            ttk.Entry(parent, textvariable=var, state="readonly").grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))
        else:
            ttk.Entry(parent, textvariable=var).grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))


def _setup_production_packing_calculation(field_vars: dict[str, object]) -> None:
    required_keys = {"unit_per_carton", "carton_qty", "odd_carton_qty", "odd_carton_dimension"}
    if not required_keys.issubset(field_vars):
        return

    def get_text(key: str) -> str:
        variable = field_vars.get(key)
        if hasattr(variable, "get"):
            return str(variable.get() or "").strip()
        return ""

    def set_text(key: str, value: str) -> None:
        variable = field_vars.get(key)
        if hasattr(variable, "set"):
            variable.set(value)

    def recalculate(*_args: object) -> None:
        ship_qty = get_text("ship_qty")
        if not ship_qty:
            total_color_ship_qty = sum(
                _safe_float_value(variable.get())
                for key, variable in field_vars.items()
                if str(key).startswith("color_qty::") and str(key).endswith("::ship_qty") and hasattr(variable, "get")
            )
            ship_qty = _format_number(total_color_ship_qty) if total_color_ship_qty else ""
        row = {
            "ship_qty": ship_qty,
            "unit_per_carton": get_text("unit_per_carton"),
        }
        _recalculate_production_packing(row)
        set_text("carton_qty", str(row.get("carton_qty", "") or ""))
        set_text("odd_carton_qty", str(row.get("odd_carton_qty", "") or ""))
        set_text("odd_carton_dimension", str(row.get("odd_carton_dimension", "") or ""))

    trace_keys = ["unit_per_carton"]
    if "ship_qty" in field_vars:
        trace_keys.append("ship_qty")
    trace_keys.extend(
        key
        for key in field_vars
        if str(key).startswith("color_qty::") and str(key).endswith("::ship_qty")
    )
    for key in trace_keys:
        variable = field_vars.get(key)
        if hasattr(variable, "trace_add"):
            variable.trace_add("write", recalculate)
    recalculate()


def _build_production_po_line_items_section(self, parent: ttk.Frame, row: dict, field_vars: dict[str, tk.StringVar], *, start_row: int) -> None:
    parent.rowconfigure(start_row + 2, weight=1)
    summary = ttk.Frame(parent)
    summary.grid(row=start_row, column=0, columnspan=2, sticky="ew", pady=(12, 8))
    summary.columnconfigure(1, weight=1)
    color_summaries = _production_color_summaries(self, row)
    ttk.Label(summary, text="Color count").grid(row=0, column=0, sticky="w", padx=(0, 8))
    ttk.Label(summary, text=str(len(color_summaries)), relief="sunken", anchor="w", padding=(8, 3)).grid(row=0, column=1, sticky="ew")

    ttk.Label(parent, text="PO Detail Line Items by Color", style="Section.TLabel").grid(row=start_row + 1, column=0, columnspan=2, sticky="w", pady=(0, 6))
    color_notebook = ttk.Notebook(parent)
    color_notebook.grid(row=start_row + 2, column=0, columnspan=2, sticky="nsew")
    if not color_summaries:
        empty_frame = ttk.Frame(color_notebook, padding=12)
        color_notebook.add(empty_frame, text="No Color")
        ttk.Label(empty_frame, text="No PO line item data found.", foreground="#5f6b7a").pack(anchor="w")
        return
    for summary_row in color_summaries:
        color_label = str(summary_row.get("color_label", "") or "No Color")
        table_frame = ttk.Frame(color_notebook, padding=(0, 8, 0, 0))
        color_notebook.add(table_frame, text=color_label[:28] or "No Color")
        _build_production_color_quantity_summary(self, table_frame, summary_row, field_vars)
        _build_production_po_color_line_items_tree(self, table_frame, list(summary_row.get("items", []) or []), start_row=9)


def _build_production_materials_section(self, parent: ttk.Frame, row: dict, field_vars: dict[str, object]) -> None:
    parent.rowconfigure(2, weight=1)
    parent.columnconfigure(0, weight=1)
    material_rows = self.build_production_material_rows_from_consumption(row) if hasattr(self, "build_production_material_rows_from_consumption") else []
    field_vars["materials_json"] = tk.StringVar(value=_production_dump_materials_json(material_rows))

    base_qty = _safe_float_value(row.get("ship_qty")) or _safe_float_value(row.get("order_qty"))
    summary = ttk.Frame(parent)
    summary.grid(row=0, column=0, sticky="ew", pady=(0, 10))
    summary.columnconfigure(1, weight=1)
    ttk.Label(summary, text="Material source").grid(row=0, column=0, sticky="w", padx=(0, 8))
    source_text = f"Tech Pack Consumption > Production | Base qty: {_format_number(base_qty)}" if material_rows else "No Production consumption lines found."
    ttk.Label(summary, text=source_text, relief="sunken", anchor="w", padding=(8, 3)).grid(row=0, column=1, sticky="ew")

    ttk.Label(parent, text="Materials", style="Section.TLabel").grid(row=1, column=0, sticky="w", pady=(0, 6))
    table_frame = ttk.Frame(parent)
    table_frame.grid(row=2, column=0, sticky="nsew")
    table_frame.columnconfigure(0, weight=1)
    table_frame.rowconfigure(0, weight=1)

    tree = ttk.Treeview(
        table_frame,
        columns=PRODUCTION_MATERIAL_COLUMNS,
        show="headings",
        selectmode="browse",
        style="Costing.Treeview",
        height=12,
    )
    labels = {
        "costing_id": "Costing ID",
        "item_code": "Item Code",
        "item_name": "Name",
        "type": "Type",
        "section": "Section",
        "color": "Color",
        "consumption": "Consumption",
        "uom": "UOM",
        "waste_percent": "Waste %",
        "required_qty": "Required Qty",
        "fabric_weight": "Fabric Weight",
        "note": "Note",
    }
    widths = {
        "costing_id": 150,
        "item_code": 140,
        "item_name": 220,
        "type": 100,
        "section": 110,
        "color": 130,
        "consumption": 110,
        "uom": 70,
        "waste_percent": 90,
        "required_qty": 110,
        "fabric_weight": 120,
        "note": 190,
    }
    for column_key in PRODUCTION_MATERIAL_COLUMNS:
        tree.column(column_key, width=widths.get(column_key, 100), anchor="w", stretch=column_key in {"item_name", "note"})
        tree.heading(column_key, text=labels.get(column_key, column_key))
    configure_striped_treeview(tree)
    scroll_y = ttk.Scrollbar(table_frame, orient="vertical", command=tree.yview)
    scroll_x = ttk.Scrollbar(table_frame, orient="horizontal", command=tree.xview)
    tree.configure(yscrollcommand=scroll_y.set, xscrollcommand=scroll_x.set)
    tree.grid(row=0, column=0, sticky="nsew")
    scroll_y.grid(row=0, column=1, sticky="ns")
    scroll_x.grid(row=1, column=0, sticky="ew")
    editable_material_columns = {"consumption", "fabric_weight"}
    material_rows_by_iid: dict[str, dict] = {}

    def update_materials_json() -> None:
        variable = field_vars.get("materials_json")
        if hasattr(variable, "set"):
            variable.set(_production_dump_materials_json(list(material_rows_by_iid.values())))

    def begin_material_cell_edit(event: tk.Event) -> None:
        region = tree.identify("region", event.x, event.y)
        if region != "cell":
            return
        row_iid = tree.identify_row(event.y)
        column_id = tree.identify_column(event.x)
        if not row_iid or row_iid == "empty" or not column_id.startswith("#"):
            return
        try:
            column_key = PRODUCTION_MATERIAL_COLUMNS[int(column_id[1:]) - 1]
        except (ValueError, IndexError):
            return
        if column_key not in editable_material_columns:
            return
        cell_bbox = tree.bbox(row_iid, column_id)
        if not cell_bbox:
            return
        x, y, width, height = cell_bbox
        current_value = str(tree.set(row_iid, column_key) or "")
        if current_value == "-":
            current_value = ""
        editor = ttk.Entry(tree)
        editor.insert(0, current_value)
        editor.select_range(0, "end")
        editor.place(x=x, y=y, width=width, height=height)
        editor.focus_set()

        def commit_edit(_event: object = None) -> str:
            next_value = str(editor.get() or "").strip()
            if row_iid in material_rows_by_iid:
                material_rows_by_iid[row_iid][column_key] = next_value
                if column_key == "consumption":
                    required_qty = base_qty * _safe_float_value(next_value) * (
                        1 + _safe_float_value(material_rows_by_iid[row_iid].get("waste_percent")) / 100
                    )
                    required_qty_text = _format_number(required_qty) if required_qty and base_qty else ""
                    material_rows_by_iid[row_iid]["required_qty"] = required_qty_text
                    tree.set(row_iid, "required_qty", required_qty_text if required_qty_text else "-")
                tree.set(row_iid, column_key, next_value if next_value else "-")
                update_materials_json()
            try:
                editor.destroy()
            except tk.TclError:
                pass
            return "break"

        def cancel_edit(_event: object = None) -> str:
            try:
                editor.destroy()
            except tk.TclError:
                pass
            return "break"

        editor.bind("<Return>", commit_edit)
        editor.bind("<KP_Enter>", commit_edit)
        editor.bind("<FocusOut>", commit_edit)
        editor.bind("<Escape>", cancel_edit)

    tree.bind("<Double-1>", begin_material_cell_edit)
    if not material_rows:
        tree.insert("", "end", iid="empty", values=tuple("No Production consumption line yet." if key == "item_name" else "" for key in PRODUCTION_MATERIAL_COLUMNS), tags=("odd_row",))
        return
    for index, material_row in enumerate(material_rows, start=1):
        row_iid = str(index)
        material_rows_by_iid[row_iid] = dict(material_row)
        values = tuple(self.display_value(material_row.get(key)) for key in PRODUCTION_MATERIAL_COLUMNS)
        tree.insert("", "end", iid=row_iid, values=values, tags=("odd_row" if index % 2 == 1 else "even_row",))


def _production_line_item_color_label(item: dict) -> str:
    color = str(item.get("mfg_color") or item.get("color") or item.get("color_label") or "").strip()
    return color or "No Color"


def _production_group_line_items_by_color(items: list[dict]) -> list[tuple[str, list[dict]]]:
    grouped: dict[str, tuple[str, list[dict]]] = {}
    for item in list(items or []):
        if not isinstance(item, dict):
            continue
        color_label = _production_line_item_color_label(item)
        color_key = color_label.lower()
        if color_key not in grouped:
            grouped[color_key] = (color_label, [])
        grouped[color_key][1].append(dict(item))
    return sorted(grouped.values(), key=lambda pair: pair[0].lower())


def _production_color_storage_key(color_label: object) -> str:
    normalized = " ".join(str(color_label or "No Color").strip().lower().split())
    return normalized or "no color"


def _load_production_color_quantity_map(row: dict) -> dict[str, dict]:
    raw_value = str(row.get("color_quantity_json", "") or "").strip()
    if not raw_value:
        return {}
    try:
        payload = json.loads(raw_value)
    except Exception:
        return {}
    if not isinstance(payload, dict):
        return {}
    normalized: dict[str, dict] = {}
    for key, value in payload.items():
        if isinstance(value, dict):
            normalized[str(key)] = {str(inner_key): str(inner_value or "").strip() for inner_key, inner_value in value.items()}
    return normalized


def _dump_production_color_quantity_map(payload: dict[str, dict]) -> str:
    compact: dict[str, dict[str, str]] = {}
    for color_key, row in dict(payload or {}).items():
        if not isinstance(row, dict):
            continue
        values = {str(key): str(value or "").strip() for key, value in row.items() if str(value or "").strip()}
        if values:
            compact[str(color_key)] = values
    return json.dumps(compact, ensure_ascii=False, separators=(",", ":")) if compact else ""


def _production_color_summary_from_items(self, color_label: str, items: list[dict], row: dict) -> dict[str, object]:
    size_labels, pack_qty_by_size, order_qty_by_size = _production_size_breakdown_from_items(self, items)
    order_qty = sum(order_qty_by_size.get(size, 0.0) for size in size_labels)
    saved_color_map = _load_production_color_quantity_map(row)
    color_key = _production_color_storage_key(color_label)
    saved_row = dict(saved_color_map.get(color_key, {}))
    ship_qty = _safe_float_value(saved_row.get("ship_qty"))
    if ship_qty <= 0:
        ship_qty = order_qty
    diff = ship_qty - order_qty
    return {
        "color_key": color_key,
        "color_label": color_label,
        "items": list(items or []),
        "size_labels": size_labels,
        "pack_qty_by_size": pack_qty_by_size,
        "order_qty_by_size": order_qty_by_size,
        "unit_per_pack": _format_number(sum(pack_qty_by_size.get(size, 0.0) for size in size_labels)),
        "size_range": "-".join(size_labels),
        "size_scale": "-".join(_format_number(pack_qty_by_size.get(size, 0.0)) for size in size_labels),
        "order_qty": _format_number(order_qty),
        "ship_qty": _format_number(ship_qty),
        "over_short_ship_qty": _format_number(diff),
        "over_short_ship_percent": f"{_format_number(diff / order_qty * 100)}%" if order_qty else "",
    }


def _production_color_summaries(self, row: dict) -> list[dict[str, object]]:
    grouped_items = _production_group_line_items_by_color(self.get_production_po_detail_line_items(row))
    return [
        _production_color_summary_from_items(self, color_label, color_items, row)
        for color_label, color_items in grouped_items
    ]


def _build_production_color_quantity_summary(self, parent: ttk.Frame, summary_row: dict[str, object], field_vars: dict[str, tk.StringVar]) -> None:
    color_key = str(summary_row.get("color_key", "") or "")
    fields = [
        ("size_range", "Size Range", True),
        ("size_scale", "Size Scale", True),
        ("order_qty", "Order Qty", True),
        ("ship_qty", "Ship Qty", False),
        ("over_short_ship_qty", "Over/Short ship qty", True),
        ("over_short_ship_percent", "Over/Short ship %", True),
        ("unit_per_pack", "Unit per pack", True),
    ]
    variables: dict[str, tk.StringVar] = {}
    for index, (key, label, readonly) in enumerate(fields):
        row_index = index // 2 * 2
        column_index = index % 2
        parent.columnconfigure(column_index, weight=1)
        ttk.Label(parent, text=label).grid(row=row_index, column=column_index, sticky="w", padx=(0, 12), pady=(0, 4))
        variable = tk.StringVar(value=str(summary_row.get(key, "") or ""))
        variables[key] = variable
        field_vars[f"color_qty::{color_key}::{key}"] = variable
        ttk.Entry(parent, textvariable=variable, state="readonly" if readonly else "normal").grid(row=row_index + 1, column=column_index, sticky="ew", padx=(0, 12), pady=(0, 8))

    def recalculate(*_args: object) -> None:
        order_qty = _safe_float_value(variables["order_qty"].get())
        ship_qty = _safe_float_value(variables["ship_qty"].get())
        diff = ship_qty - order_qty
        variables["over_short_ship_qty"].set(_format_number(diff))
        variables["over_short_ship_percent"].set(f"{_format_number(diff / order_qty * 100)}%" if order_qty else "")

    variables["ship_qty"].trace_add("write", recalculate)
    recalculate()


def _build_production_po_color_line_items_tree(self, table_frame: ttk.Frame, line_items: list[dict], *, start_row: int = 0) -> None:
    table_frame.columnconfigure(0, weight=1)
    table_frame.rowconfigure(start_row, weight=1)

    tree = ttk.Treeview(
        table_frame,
        columns=PRODUCTION_PO_LINE_ITEM_COLUMNS,
        show="headings",
        selectmode="browse",
        style="Costing.Treeview",
        height=7,
    )
    labels = {
        "sku": "SKU",
        "mfg_style": "Style",
        "mfg_color": "Color",
        "size_desc": "Size",
        "description": "Description",
        "upc": "UPC",
        "cost_unit": "Cost",
        "comp": "Comp",
        "retail": "Retail",
        "pack_qty": "Pack Qty",
        "total_packs": "Total Packs",
        "total_units": "Total Units",
    }
    widths = {
        "sku": 90,
        "mfg_style": 90,
        "mfg_color": 150,
        "size_desc": 70,
        "description": 260,
        "upc": 130,
        "cost_unit": 80,
        "comp": 80,
        "retail": 80,
        "pack_qty": 80,
        "total_packs": 95,
        "total_units": 95,
    }
    for column_key in PRODUCTION_PO_LINE_ITEM_COLUMNS:
        tree.column(column_key, width=widths.get(column_key, 100), anchor="w", stretch=column_key == "description")
        tree.heading(column_key, text=labels.get(column_key, column_key))
    configure_striped_treeview(tree)
    scroll_y = ttk.Scrollbar(table_frame, orient="vertical", command=tree.yview)
    scroll_x = ttk.Scrollbar(table_frame, orient="horizontal", command=tree.xview)
    tree.configure(yscrollcommand=scroll_y.set, xscrollcommand=scroll_x.set)
    tree.grid(row=start_row, column=0, columnspan=2, sticky="nsew", pady=(10, 0))
    scroll_y.grid(row=start_row, column=2, sticky="ns", pady=(10, 0))
    scroll_x.grid(row=start_row + 1, column=0, columnspan=2, sticky="ew")
    for index, item in enumerate(line_items, start=1):
        values = tuple(self.display_value(item.get(key)) for key in PRODUCTION_PO_LINE_ITEM_COLUMNS)
        tree.insert("", "end", iid=str(index), values=values, tags=("odd_row" if index % 2 == 1 else "even_row",))


def save_production_detail_window(self, original_row: dict, field_vars: dict[str, object], dialog: tk.Toplevel) -> None:
    record_id = str(original_row.get("record_id", "")).strip()
    updated = dict(original_row)
    for key, var in field_vars.items():
        if key.endswith("::__text_widget"):
            continue
        if key.startswith("color_qty::"):
            continue
        if hasattr(var, "get"):
            updated[key] = str(var.get() or "").strip()
    color_quantity_map: dict[str, dict[str, str]] = {}
    for key, var in field_vars.items():
        if not key.startswith("color_qty::") or not hasattr(var, "get"):
            continue
        parts = key.split("::", 2)
        if len(parts) != 3:
            continue
        _prefix, color_key, field_key = parts
        if field_key not in {"ship_qty"}:
            continue
        color_quantity_map.setdefault(color_key, {})[field_key] = str(var.get() or "").strip()
    if color_quantity_map:
        updated["color_quantity_json"] = _dump_production_color_quantity_map(color_quantity_map)
        total_ship_qty = sum(_safe_float_value(payload.get("ship_qty")) for payload in color_quantity_map.values())
        updated["ship_qty"] = _format_number(total_ship_qty)
    notes_widget = field_vars.get("notes::__text_widget")
    if hasattr(notes_widget, "get"):
        updated["notes"] = str(notes_widget.get("1.0", "end-1c") or "").strip()
    updated["updated_at"] = _production_now_text()
    _recalculate_production_packing(updated)
    material_sync_count = 0
    if str(updated.get("materials_json", "") or "").strip():
        try:
            material_sync_count = self.sync_production_material_edits_to_tech_pack(updated)
        except Exception as exc:
            _append_production_debug_log(f"save detail materials sync failed: {exc}")
            messagebox.showerror(self.t("warning_title"), f"Could not sync Materials to Tech Pack:\n{exc}")
            return
    else:
        try:
            updated["materials_json"] = _production_dump_materials_json(self.build_production_material_rows_from_consumption(updated))
        except Exception as exc:
            _append_production_debug_log(f"save detail materials snapshot failed: {exc}")
    normalized = normalize_production_order_row(updated)
    if not isinstance(normalized, dict):
        messagebox.showerror(self.t("warning_title"), "Could not save Production Order.")
        return
    try:
        saved_overlay = self.save_production_detail_row_to_source(normalized)
    except Exception as exc:
        messagebox.showerror(self.t("warning_title"), str(exc))
        return
    style_season_key = _production_style_season_key(normalized)
    shared_values = _production_shared_fields_from_row(normalized)
    updated_at = str(normalized.get("updated_at", "") or "").strip()
    rows = []
    replaced = False
    for row in getattr(self, "production_rows", []) or []:
        row_id = str(row.get("record_id", "")).strip()
        if row_id == record_id:
            rows.append(normalized)
            replaced = True
        elif style_season_key[0] and _production_style_season_key(row) == style_season_key:
            rows.append(_apply_production_shared_fields(dict(row), shared_values, updated_at=updated_at))
        else:
            rows.append(dict(row))
    if not replaced:
        rows.append(normalized)
    self.production_rows = rows
    self.apply_production_filter()
    if hasattr(self, "save_main_ui_local_cache_records_async"):
        self.save_main_ui_local_cache_records_async("production", self.production_rows)
    if hasattr(self, "save_main_ui_session_cache"):
        self.save_main_ui_session_cache(
            "production",
            {
                "tech_pack_library": list(getattr(self, "tech_pack_library", []) or []),
                "production_rows": self.production_rows,
            },
        )
    sync_suffix = f" | Synced {material_sync_count} material field change(s) to Tech Pack Production" if material_sync_count else ""
    self.set_status(f"Saved Production Order: {saved_overlay.get('production_order', normalized.get('production_order', ''))}{sync_suffix}")
    self.close_production_detail_window(dialog)


def bind_production_module(app_cls: type) -> None:
    for name, value in {
        "_build_production_module": _build_production_module,
        "load_production_rows_from_source": load_production_rows_from_source,
        "save_production_rows_to_source": save_production_rows_to_source,
        "save_production_saved_detail_rows_to_source": save_production_saved_detail_rows_to_source,
        "save_production_detail_row_to_source": save_production_detail_row_to_source,
        "delete_production_detail_rows_from_source": delete_production_detail_rows_from_source,
        "load_production_factory_rows_from_source": load_production_factory_rows_from_source,
        "save_production_factory_rows_to_source": save_production_factory_rows_to_source,
        "save_production_factory_row_to_source": save_production_factory_row_to_source,
        "delete_production_factory_row_from_source": delete_production_factory_row_from_source,
        "get_active_production_factory_names": get_active_production_factory_names,
        "get_production_po_detail_line_items": get_production_po_detail_line_items,
        "production_unit_per_pack": production_unit_per_pack,
        "sync_production_material_edits_to_tech_pack": sync_production_material_edits_to_tech_pack,
        "build_production_material_rows_from_consumption": build_production_material_rows_from_consumption,
        "restore_production_detail_window_state": restore_production_detail_window_state,
        "capture_production_detail_window_state": capture_production_detail_window_state,
        "close_production_detail_window": close_production_detail_window,
        "build_production_rows_from_purchase_orders": build_production_rows_from_purchase_orders,
        "refresh_production_module": refresh_production_module,
        "configure_production_filter_options": configure_production_filter_options,
        "update_production_filter_input_state": update_production_filter_input_state,
        "apply_production_filter": apply_production_filter,
        "production_row_matches_filter": production_row_matches_filter,
        "get_active_production_filters": get_active_production_filters,
        "add_production_filter_row": add_production_filter_row,
        "remove_production_filter_row": remove_production_filter_row,
        "clear_production_filters": clear_production_filters,
        "refresh_production_tree": refresh_production_tree,
        "create_production_thumbnail": create_production_thumbnail,
        "update_production_module_status": update_production_module_status,
        "get_selected_production_record_id": get_selected_production_record_id,
        "get_selected_production_row": get_selected_production_row,
        "on_production_heading_click": on_production_heading_click,
        "update_production_tree_check_cell": update_production_tree_check_cell,
        "on_production_tree_click": on_production_tree_click,
        "on_production_double_click": on_production_double_click,
        "on_production_filter_field_changed": on_production_filter_field_changed,
        "on_production_sort_key_changed": on_production_sort_key_changed,
        "on_production_sort_order_changed": on_production_sort_order_changed,
        "on_production_search_submit": on_production_search_submit,
        "edit_selected_production_order": edit_selected_production_order,
        "delete_selected_production_order": delete_selected_production_order,
        "load_production_packing_list_assets_from_source": load_production_packing_list_assets_from_source,
        "save_production_packing_list_assets_to_source": save_production_packing_list_assets_to_source,
        "load_production_carton_sticker_assets_from_source": load_production_carton_sticker_assets_from_source,
        "save_production_carton_sticker_assets_to_source": save_production_carton_sticker_assets_to_source,
        "resolve_production_packing_list_template_asset": resolve_production_packing_list_template_asset,
        "ensure_production_packing_list_template_asset": ensure_production_packing_list_template_asset,
        "export_selected_production_packing_list": export_selected_production_packing_list,
        "ensure_production_liquidation_template_asset": ensure_production_liquidation_template_asset,
        "export_selected_production_liquidation": export_selected_production_liquidation,
        "ensure_production_carton_sticker_template_asset": ensure_production_carton_sticker_template_asset,
        "export_selected_production_carton_stickers": export_selected_production_carton_stickers,
        "get_selected_production_factory_id": get_selected_production_factory_id,
        "get_selected_production_factory_row": get_selected_production_factory_row,
        "refresh_production_factory_tree": refresh_production_factory_tree,
        "apply_production_factory_filter": apply_production_factory_filter,
        "refresh_production_factory_list_window": refresh_production_factory_list_window,
        "on_production_factory_search_submit": on_production_factory_search_submit,
        "open_production_factory_detail_window": open_production_factory_detail_window,
        "open_new_production_factory_dialog": open_new_production_factory_dialog,
        "edit_selected_production_factory_row": edit_selected_production_factory_row,
        "delete_selected_production_factory_row": delete_selected_production_factory_row,
        "on_production_factory_row_selected": on_production_factory_row_selected,
        "on_production_factory_row_double_click": on_production_factory_row_double_click,
        "open_production_factory_list_window": open_production_factory_list_window,
        "close_production_factory_list_window": close_production_factory_list_window,
        "export_production_report": export_production_report,
        "open_production_order_detail_window": open_production_order_detail_window,
        "_build_production_materials_section": _build_production_materials_section,
        "save_production_detail_window": save_production_detail_window,
        "production_field_label": production_field_label,
        "production_filter_label": production_filter_label,
        "production_sort_label": production_sort_label,
    }.items():
        setattr(app_cls, name, value)
