package queries

import (
	"database/sql"
	"fmt"
	"log"
	"sort"
	"strconv"
	"strings"
	"time"

	"bssapp-backend/models"
)

// ========================================================
// 📌 GetOrderProductionItems — OrderHeaderID için U ürünleri
// ========================================================
func GetOrderProductionItems(mssql *sql.DB, orderHeaderID string) (*sql.Rows, error) {
	return mssql.Query(`
SELECT
    CAST(l.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID,
    CAST(l.OrderLineID   AS NVARCHAR(50)) AS OrderLineID,
    l.ItemTypeCode       AS ItemTypeCode,
    ISNULL(l.ItemDim1Code,'') AS OldDim1,
    ISNULL(l.ItemDim3Code,'') AS OldDim3,

    ISNULL(l.ItemCode,'')      AS OldItemCode,
    ISNULL(l.ColorCode,'')     AS OldColor,
    ISNULL((
        SELECT TOP 1 LTRIM(RTRIM(cd.ColorDescription))
        FROM dbo.cdColorDesc cd
        WHERE cd.ColorCode = l.ColorCode
          AND cd.LangCode = N'TR'
    ), '') AS OldColorDescription,
    ISNULL(l.ItemDim2Code,'')  AS OldDim2,
    ISNULL(l.LineDescription,'') AS OldDesc,
    CAST(ISNULL(l.Qty1, 0) AS FLOAT) AS OldQty,

    ISNULL(h.DocCurrencyCode,'TRY') AS OldDocCurrencyCode,
    CAST(ISNULL(c.NetAmount, 0) AS FLOAT) AS OldNetAmount,
    CAST(
        CASE
            WHEN ISNULL(h.DocCurrencyCode,'TRY') = 'USD'
                THEN ISNULL(c.NetAmount,0)

            WHEN ISNULL(h.DocCurrencyCode,'TRY') = 'TRY'
                 AND usd.Rate > 0
                THEN ISNULL(c.NetAmount,0) / usd.Rate

            WHEN ISNULL(h.DocCurrencyCode,'TRY') IN ('EUR','GBP')
                 AND cur.Rate > 0
                 AND usd.Rate > 0
                THEN (ISNULL(c.NetAmount,0) * cur.Rate) / usd.Rate

            ELSE 0
        END
    AS FLOAT) AS OldNetAmountUSD,

    CAST('' AS NVARCHAR(60))   AS NewItemCode,
    CAST('' AS NVARCHAR(30))   AS NewColor,
    CAST('' AS NVARCHAR(30))   AS NewDim2,
    CAST('' AS NVARCHAR(250))  AS NewDesc,

    CONVERT(NVARCHAR(10), l.DeliveryDate, 126) AS OldDueDate,
    CONVERT(NVARCHAR(10), l.DeliveryDate, 126) AS NewDueDate,

    CAST(0 AS bit) AS IsVariantMissing
FROM dbo.trOrderLine l
JOIN dbo.trOrderHeader h
  ON h.OrderHeaderID = l.OrderHeaderID
LEFT JOIN dbo.trOrderLineCurrency c
  ON c.OrderLineID  = l.OrderLineID
 AND c.CurrencyCode = ISNULL(h.DocCurrencyCode,'TRY')

OUTER APPLY (
    SELECT TOP 1 Rate
    FROM dbo.AllExchangeRates
    WHERE CurrencyCode = 'USD'
      AND RelationCurrencyCode = 'TRY'
      AND ExchangeTypeCode = 6
      AND Rate > 0
      AND Date <= CAST(GETDATE() AS date)
    ORDER BY Date DESC
) usd

OUTER APPLY (
    SELECT TOP 1 Rate
    FROM dbo.AllExchangeRates
    WHERE CurrencyCode = ISNULL(h.DocCurrencyCode,'TRY')
      AND RelationCurrencyCode = 'TRY'
      AND ExchangeTypeCode = 6
      AND Rate > 0
      AND Date <= CAST(GETDATE() AS date)
    ORDER BY Date DESC
) cur
WHERE l.OrderHeaderID = @p1
  AND ISNULL(l.ItemCode,'') LIKE 'U%'
ORDER BY l.SortOrder, l.OrderLineID
`, orderHeaderID)
}

// ========================================================
// 📌 InsertMissingProductionVariants — eksik prItemVariant ekler
// ========================================================
func InsertMissingProductionVariants(mssql *sql.DB, orderHeaderID string, username string) (int64, error) {
	query := `
;WITH Missing AS (
    SELECT DISTINCT
        l.ItemTypeCode,
        l.ItemCode,
        l.ColorCode,
        l.ItemDim1Code,
        l.ItemDim2Code,
        l.ItemDim3Code
    FROM dbo.trOrderLine l
    LEFT JOIN dbo.prItemVariant pv
      ON pv.ItemTypeCode = l.ItemTypeCode
     AND ISNULL(LTRIM(RTRIM(pv.ItemCode)),'') = ISNULL(LTRIM(RTRIM(l.ItemCode)),'')
     AND ISNULL(LTRIM(RTRIM(pv.ColorCode)),'') = ISNULL(LTRIM(RTRIM(l.ColorCode)),'')
     AND ISNULL(LTRIM(RTRIM(pv.ItemDim1Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim1Code)),'')
     AND ISNULL(LTRIM(RTRIM(pv.ItemDim2Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim2Code)),'')
     AND ISNULL(LTRIM(RTRIM(pv.ItemDim3Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim3Code)),'')
    WHERE l.OrderHeaderID = @p1
      AND ISNULL(l.ItemCode,'') LIKE 'U%'
      AND pv.ItemCode IS NULL
)
INSERT INTO dbo.prItemVariant (
    ItemTypeCode,
    ItemCode,
    ColorCode,
    ItemDim1Code,
    ItemDim2Code,
    ItemDim3Code,
    IsSalesOrderClosed,
    IsPurchaseOrderClosed,
    IsLocked,
    IsBlocked,
    CreatedUserName,
    CreatedDate,
    LastUpdatedUserName,
    LastUpdatedDate,
    RowGuid,
    UseInternet,
    IsStoreOrderClosed
)
SELECT
    m.ItemTypeCode,
    m.ItemCode,
    m.ColorCode,
    m.ItemDim1Code,
    m.ItemDim2Code,
    m.ItemDim3Code,
    0,
    0,
    0,
    0,
    @p2,
    GETDATE(),
    @p2,
    GETDATE(),
    NEWID(),
    0,
    0
FROM Missing m;
`

	res, err := mssql.Exec(query, orderHeaderID, username)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

// ========================================================
// OrderProductionUpdate - variant kontrolu ve guncelleme
// ========================================================
func GetOrderLineDims(mssql *sql.DB, orderHeaderID string, orderLineID string) (int16, string, string, string, error) {
	var itemTypeCode int16
	var dim1 string
	var dim2 string
	var dim3 string
	err := mssql.QueryRow(`
SELECT
    ItemTypeCode,
    ISNULL(ItemDim1Code,'') AS ItemDim1Code,
    ISNULL(ItemDim2Code,'') AS ItemDim2Code,
    ISNULL(ItemDim3Code,'') AS ItemDim3Code
FROM dbo.trOrderLine
WHERE OrderHeaderID = @p1 AND OrderLineID = @p2
`, orderHeaderID, orderLineID).Scan(&itemTypeCode, &dim1, &dim2, &dim3)
	return itemTypeCode, dim1, dim2, dim3, err
}

type OrderLineDims struct {
	ItemTypeCode int16
	ItemDim1Code string
	ItemDim2Code string
	ItemDim3Code string
}

func GetOrderLineDimsMap(mssql *sql.DB, orderHeaderID string) (map[string]OrderLineDims, error) {
	rows, err := mssql.Query(`
SELECT
    CAST(OrderLineID AS NVARCHAR(50)) AS OrderLineID,
    ItemTypeCode,
    ISNULL(ItemDim1Code,'') AS ItemDim1Code,
    ISNULL(ItemDim2Code,'') AS ItemDim2Code,
    ISNULL(ItemDim3Code,'') AS ItemDim3Code
FROM dbo.trOrderLine
WHERE OrderHeaderID = @p1
`, orderHeaderID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	out := make(map[string]OrderLineDims, 128)
	for rows.Next() {
		var lineID string
		var d OrderLineDims
		if err := rows.Scan(&lineID, &d.ItemTypeCode, &d.ItemDim1Code, &d.ItemDim2Code, &d.ItemDim3Code); err != nil {
			return nil, err
		}
		out[strings.TrimSpace(lineID)] = d
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return out, nil
}

func VariantExists(mssql *sql.DB, itemTypeCode int16, itemCode string, colorCode string, dim1 string, dim2 string, dim3 string) (bool, error) {
	var exists int
	err := mssql.QueryRow(`
SELECT TOP 1 1
FROM dbo.prItemVariant
WHERE ItemTypeCode = @p1
  AND ItemCode = @p2
  AND (
        ColorCode = @p3
        OR (@p3 = '' AND (ColorCode IS NULL OR ColorCode = ''))
      )
  AND (
        ItemDim1Code = @p4
        OR (@p4 = '' AND (ItemDim1Code IS NULL OR ItemDim1Code = ''))
      )
  AND (
        ItemDim2Code = @p5
        OR (@p5 = '' AND (ItemDim2Code IS NULL OR ItemDim2Code = ''))
      )
  AND (
        ItemDim3Code = @p6
        OR (@p6 = '' AND (ItemDim3Code IS NULL OR ItemDim3Code = ''))
      )
`, itemTypeCode, itemCode, colorCode, dim1, dim2, dim3).Scan(&exists)
	if err == sql.ErrNoRows {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

func InsertMissingVariantsTx(
	tx *sql.Tx,
	missing []models.OrderProductionMissingVariant,
	username string,
	cdItemByCode map[string]models.OrderProductionCdItemDraft,
) (int64, error) {
	start := time.Now()
	if len(missing) == 0 {
		log.Printf("[InsertMissingVariantsTx] missing=0 inserted=0 duration_ms=0")
		return 0, nil
	}

	var inserted int64
	ensuredItems := make(map[string]struct{}, len(missing))
	uniqueVariants := make([]models.OrderProductionMissingVariant, 0, len(missing))
	seenVariants := make(map[string]struct{}, len(missing))

	for _, v := range missing {
		variantKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" +
			strings.ToUpper(strings.TrimSpace(v.ItemCode)) + "|" +
			strings.ToUpper(strings.TrimSpace(v.ColorCode)) + "|" +
			strings.ToUpper(strings.TrimSpace(v.ItemDim1Code)) + "|" +
			strings.ToUpper(strings.TrimSpace(v.ItemDim2Code)) + "|" +
			strings.ToUpper(strings.TrimSpace(v.ItemDim3Code))
		if _, ok := seenVariants[variantKey]; ok {
			continue
		}
		seenVariants[variantKey] = struct{}{}
		uniqueVariants = append(uniqueVariants, v)

		itemKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" + v.ItemCode
		if _, ok := ensuredItems[itemKey]; !ok {
			draft, hasDraft := cdItemByCode[itemKey]
			if !hasDraft {
				draft, hasDraft = cdItemByCode[NormalizeCdItemMapKey(v.ItemTypeCode, v.ItemCode)]
			}
			var draftPtr *models.OrderProductionCdItemDraft
			if hasDraft {
				tmp := draft
				draftPtr = &tmp
			}
			if err := ensureCdItemTx(tx, v.ItemTypeCode, v.ItemCode, username, draftPtr); err != nil {
				return inserted, err
			}
			ensuredItems[itemKey] = struct{}{}
		}
	}

	if len(uniqueVariants) == 0 {
		return 0, nil
	}

	args := make([]any, 0, len(uniqueVariants)*6+1)
	valueRows := make([]string, 0, len(uniqueVariants))
	paramPos := 1
	for _, v := range uniqueVariants {
		valueRows = append(valueRows, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3, paramPos+4, paramPos+5))
		args = append(args, v.ItemTypeCode, v.ItemCode, v.ColorCode, v.ItemDim1Code, v.ItemDim2Code, v.ItemDim3Code)
		paramPos += 6
	}
	usernameParam := paramPos
	args = append(args, username)

	query := fmt.Sprintf(`
SET NOCOUNT ON;
;WITH Missing(ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code) AS (
	SELECT *
	FROM (VALUES %s) AS v(ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code)
)
INSERT INTO dbo.prItemVariant (
	ItemTypeCode,
	ItemCode,
	ColorCode,
	ItemDim1Code,
	ItemDim2Code,
	ItemDim3Code,
	IsSalesOrderClosed,
	IsPurchaseOrderClosed,
	IsLocked,
	IsBlocked,
	CreatedUserName,
	CreatedDate,
	LastUpdatedUserName,
	LastUpdatedDate,
	RowGuid,
	UseInternet,
	IsStoreOrderClosed
)
SELECT
	m.ItemTypeCode,
	m.ItemCode,
	m.ColorCode,
	m.ItemDim1Code,
	m.ItemDim2Code,
	m.ItemDim3Code,
	0, 0, 0, 0,
	@p%d, GETDATE(), @p%d, GETDATE(),
	NEWID(),
	0,
	0
FROM Missing m
LEFT JOIN dbo.prItemVariant pv
	ON pv.ItemTypeCode = m.ItemTypeCode
	AND pv.ItemCode = m.ItemCode
	AND (
		pv.ColorCode = m.ColorCode
		OR (m.ColorCode = '' AND (pv.ColorCode IS NULL OR pv.ColorCode = ''))
	)
	AND (
		pv.ItemDim1Code = m.ItemDim1Code
		OR (m.ItemDim1Code = '' AND (pv.ItemDim1Code IS NULL OR pv.ItemDim1Code = ''))
	)
	AND (
		pv.ItemDim2Code = m.ItemDim2Code
		OR (m.ItemDim2Code = '' AND (pv.ItemDim2Code IS NULL OR pv.ItemDim2Code = ''))
	)
	AND (
		pv.ItemDim3Code = m.ItemDim3Code
		OR (m.ItemDim3Code = '' AND (pv.ItemDim3Code IS NULL OR pv.ItemDim3Code = ''))
	)
WHERE pv.ItemCode IS NULL;
`, strings.Join(valueRows, ","), usernameParam, usernameParam)

	res, err := tx.Exec(query, args...)
	if err != nil {
		return inserted, err
	}
	if rows, rowsErr := res.RowsAffected(); rowsErr == nil {
		inserted += rows
	}
	log.Printf("[InsertMissingVariantsTx] missing=%d unique=%d ensuredItems=%d inserted=%d duration_ms=%d",
		len(missing), len(uniqueVariants), len(ensuredItems), inserted, time.Since(start).Milliseconds())
	return inserted, nil
}

func NormalizeCdItemMapKey(itemTypeCode int16, itemCode string) string {
	return strconv.FormatInt(int64(itemTypeCode), 10) + "|" + strings.ToUpper(strings.TrimSpace(itemCode))
}

func ensureCdItemTx(
	tx *sql.Tx,
	itemTypeCode int16,
	itemCode string,
	username string,
	draft *models.OrderProductionCdItemDraft,
) error {
	_, err := tx.Exec(`
IF NOT EXISTS (
	SELECT 1
	FROM dbo.cdItem
	WHERE ItemTypeCode = @p1
	  AND ItemCode = @p2
)
BEGIN
	;WITH Template AS (
		SELECT TOP 1
			ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
			UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
			UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
			GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
			ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
			PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
			CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
			IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed, UseRoll, UseBatch,
			MaxCreditCardInstallmentCount, GenerateSerialNumber, IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
			IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
		FROM dbo.cdItem WITH (UPDLOCK, HOLDLOCK)
		WHERE ItemTypeCode = @p1
		  AND ItemCode LIKE 'U%'
		ORDER BY CreatedDate DESC
	)
	INSERT INTO dbo.cdItem (
		ItemTypeCode, ItemCode,
		ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
		UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
		UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
		GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
		ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
		PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
		CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
		IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed,
		CreatedUserName, CreatedDate, LastUpdatedUserName, LastUpdatedDate, RowGuid,
		UseRoll, UseBatch, MaxCreditCardInstallmentCount, GenerateSerialNumber,
		IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
		IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
	)
	SELECT
		@p1, @p2,
		t.ItemDimTypeCode, t.ProductTypeCode, t.ProductHierarchyID,
		t.UnitOfMeasureCode1, t.UnitOfMeasureCode2, t.UnitConvertRate, t.UnitConvertRateNotFixed,
		t.UseInternet, t.UsePOS, t.UseStore, t.EnablePartnerCompanies, t.UseManufacturing, t.UseSerialNumber,
		t.GenerateOpticalDataMatrixCode, t.ByWeight, t.SupplyPeriod, t.GuaranteePeriod, t.ShelfLife, t.OrderLeadTime,
		t.ItemAccountGrCode, t.ItemTaxGrCode, t.ItemPaymentPlanGrCode, t.ItemDiscountGrCode, t.ItemVendorGrCode,
		t.PromotionGroupCode, t.PromotionGroupCode2, t.ProductCollectionGrCode, t.StorePriceLevelCode, t.PerceptionOfFashionCode,
		t.CommercialRoleCode, t.StoreCapacityLevelCode, t.CustomsTariffNumberCode, t.IsFixedExpense, t.BOMEntityCode, t.CompanyCode,
		t.IsBlocked, t.IsLocked, t.LockedDate, t.IsSalesOrderClosed, t.IsPurchaseOrderClosed,
		@p3, GETDATE(), @p3, GETDATE(), NEWID(),
		t.UseRoll, t.UseBatch, t.MaxCreditCardInstallmentCount, t.GenerateSerialNumber,
		t.IsSubsequentDeliveryForR, t.IsSubsequentDeliveryForRI,
		t.IGACommissionGroup, t.UniFreeCommissionGroup, t.CustomsProductGroupCode, t.IsUTSDeclaratedItem, t.IsStoreOrderClosed
	FROM Template t;

	IF @@ROWCOUNT = 0
	BEGIN
		INSERT INTO dbo.cdItem (
			ItemTypeCode, ItemCode,
			ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
			UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
			UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
			GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
			ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
			PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
			CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
			IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed,
			CreatedUserName, CreatedDate, LastUpdatedUserName, LastUpdatedDate, RowGuid,
			UseRoll, UseBatch, MaxCreditCardInstallmentCount, GenerateSerialNumber,
			IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
			IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
		)
		VALUES (
			@p1, @p2,
			2, 1, 2,
			'AD', '', 0, 0,
			1, 1, 1, 0, 1, 0,
			0, 0, 0, 0, 0, 0,
			'', '%10', '', '', '',
			'', '', '0', '0', '0',
			'0', '', '', 0, '', '1',
			0, 0, '1900-01-01', 0, 0,
			@p3, GETDATE(), @p3, GETDATE(), NEWID(),
			0, 0, 12, 0,
			0, 0,
			'', '', '0', 0, 0
		);
	END
END
`, itemTypeCode, itemCode, username)
	if err != nil {
		return err
	}

	if draft == nil {
		return nil
	}

	_, err = tx.Exec(`
UPDATE dbo.cdItem
SET
	ItemDimTypeCode = COALESCE(@p3, ItemDimTypeCode),
	ProductTypeCode = COALESCE(@p4, ProductTypeCode),
	ProductHierarchyID = COALESCE(@p5, ProductHierarchyID),
	UnitOfMeasureCode1 = COALESCE(NULLIF(@p6,''), UnitOfMeasureCode1),
	ItemAccountGrCode = COALESCE(NULLIF(@p7,''), ItemAccountGrCode),
	ItemTaxGrCode = CASE
		WHEN NULLIF(@p8,'') IS NULL THEN ItemTaxGrCode
		WHEN EXISTS (
			SELECT 1
			FROM dbo.cdItemTaxGr g
			WHERE LTRIM(RTRIM(g.ItemTaxGrCode)) = LTRIM(RTRIM(@p8))
		) THEN @p8
		ELSE ItemTaxGrCode
	END,
	ItemPaymentPlanGrCode = COALESCE(NULLIF(@p9,''), ItemPaymentPlanGrCode),
	ItemDiscountGrCode = COALESCE(NULLIF(@p10,''), ItemDiscountGrCode),
	ItemVendorGrCode = COALESCE(NULLIF(@p11,''), ItemVendorGrCode),
	PromotionGroupCode = COALESCE(NULLIF(@p12,''), PromotionGroupCode),
	ProductCollectionGrCode = COALESCE(NULLIF(@p13,''), ProductCollectionGrCode),
	StorePriceLevelCode = COALESCE(NULLIF(@p14,''), StorePriceLevelCode),
	PerceptionOfFashionCode = COALESCE(NULLIF(@p15,''), PerceptionOfFashionCode),
	CommercialRoleCode = COALESCE(NULLIF(@p16,''), CommercialRoleCode),
	StoreCapacityLevelCode = COALESCE(NULLIF(@p17,''), StoreCapacityLevelCode),
	CustomsTariffNumberCode = COALESCE(NULLIF(@p18,''), CustomsTariffNumberCode),
	CompanyCode = COALESCE(NULLIF(@p19,''), CompanyCode),
	LastUpdatedUserName = @p20,
	LastUpdatedDate = GETDATE()
WHERE ItemTypeCode = @p1
  AND ItemCode = @p2;
`,
		itemTypeCode,
		itemCode,
		draft.ItemDimTypeCode,
		draft.ProductTypeCode,
		draft.ProductHierarchyID,
		draft.UnitOfMeasureCode1,
		draft.ItemAccountGrCode,
		draft.ItemTaxGrCode,
		draft.ItemPaymentPlanGrCode,
		draft.ItemDiscountGrCode,
		draft.ItemVendorGrCode,
		draft.PromotionGroupCode,
		draft.ProductCollectionGrCode,
		draft.StorePriceLevelCode,
		draft.PerceptionOfFashionCode,
		draft.CommercialRoleCode,
		draft.StoreCapacityLevelCode,
		draft.CustomsTariffNumberCode,
		draft.CompanyCode,
		username,
	)
	return err
}

func UpdateOrderLinesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine, username string) (int64, error) {
	if len(lines) == 0 {
		return 0, nil
	}

	const chunkSize = 300
	var updated int64

	for i := 0; i < len(lines); i += chunkSize {
		end := i + chunkSize
		if end > len(lines) {
			end = len(lines)
		}
		chunk := lines[i:end]

		values := make([]string, 0, len(chunk))
		args := make([]any, 0, len(chunk)*8+2)
		paramPos := 1
		for _, line := range chunk {
			var itemDim1 any
			if line.ItemDim1Code != nil {
				itemDim1 = strings.TrimSpace(*line.ItemDim1Code)
			}
			values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d,@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3, paramPos+4, paramPos+5, paramPos+6, paramPos+7))
			args = append(args,
				strings.TrimSpace(line.OrderLineID),
				line.NewItemCode,
				line.NewColor,
				itemDim1,
				line.NewDim2,
				line.NewDesc,
				line.OldDueDate,
				line.NewDueDate,
			)
			paramPos += 8
		}

		orderHeaderParam := paramPos
		usernameParam := paramPos + 1
		args = append(args, orderHeaderID, username)

		query := fmt.Sprintf(`
SET NOCOUNT ON;
DECLARE @updated TABLE (OrderLineID UNIQUEIDENTIFIER);

;WITH src (OrderLineID, NewItemCode, NewColor, ItemDim1Code, NewDim2, NewDesc, OldDueDate, NewDueDate) AS (
	SELECT *
	FROM (VALUES %s) AS v (OrderLineID, NewItemCode, NewColor, ItemDim1Code, NewDim2, NewDesc, OldDueDate, NewDueDate)
)
UPDATE l
SET
	l.ItemCode = s.NewItemCode,
	l.ColorCode = s.NewColor,
	l.ItemDim1Code = COALESCE(s.ItemDim1Code, l.ItemDim1Code),
	l.ItemDim2Code = s.NewDim2,
	l.LineDescription = COALESCE(NULLIF(s.NewDesc,''), l.LineDescription),
	l.DeliveryDate = CASE WHEN ISDATE(s.NewDueDate) = 1 THEN CAST(s.NewDueDate AS DATETIME) ELSE l.DeliveryDate END,
	l.LastUpdatedUserName = @p%d,
	l.LastUpdatedDate = GETDATE()
OUTPUT inserted.OrderLineID INTO @updated(OrderLineID)
FROM dbo.trOrderLine l
JOIN src s
	ON l.OrderLineID = CONVERT(UNIQUEIDENTIFIER, s.OrderLineID)
WHERE l.OrderHeaderID = CONVERT(UNIQUEIDENTIFIER, @p%d);

SELECT COUNT(1) AS UpdatedCount FROM @updated;
`, strings.Join(values, ","), usernameParam, orderHeaderParam)

		chunkStart := time.Now()
		var chunkUpdated int64
		execErr := tx.QueryRow(query, args...).Scan(&chunkUpdated)
		if execErr != nil {
			log.Printf("[UpdateOrderLinesTx] ERROR orderHeaderID=%s chunk=%d-%d err=%v", orderHeaderID, i, end, execErr)
			return updated, fmt.Errorf("update lines chunk failed chunkStart=%d chunkEnd=%d duration_ms=%d: %w", i, end, time.Since(chunkStart).Milliseconds(), execErr)
		}
		log.Printf("[UpdateOrderLinesTx] orderHeaderID=%s chunk=%d-%d updated=%d duration_ms=%d", orderHeaderID, i, end, chunkUpdated, time.Since(chunkStart).Milliseconds())
		updated += chunkUpdated
	}
	return updated, nil
}

func VerifyOrderLineUpdatesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine) (int64, []string, error) {
	if len(lines) == 0 {
		return 0, nil, nil
	}

	const chunkSize = 300
	var mismatchCount int64
	samples := make([]string, 0, 5)

	for i := 0; i < len(lines); i += chunkSize {
		end := i + chunkSize
		if end > len(lines) {
			end = len(lines)
		}
		chunk := lines[i:end]

		values := make([]string, 0, len(chunk))
		args := make([]any, 0, len(chunk)*4+1)
		paramPos := 1
		for _, line := range chunk {
			values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3))
			args = append(args,
				strings.TrimSpace(line.OrderLineID),
				strings.ToUpper(strings.TrimSpace(line.NewItemCode)),
				strings.ToUpper(strings.TrimSpace(line.NewColor)),
				strings.ToUpper(strings.TrimSpace(line.NewDim2)),
			)
			paramPos += 4
		}
		orderHeaderParam := paramPos
		args = append(args, orderHeaderID)

		query := fmt.Sprintf(`
SET NOCOUNT ON;

WITH src (OrderLineID, NewItemCode, NewColor, NewDim2) AS (
	SELECT *
	FROM (VALUES %s) v(OrderLineID, NewItemCode, NewColor, NewDim2)
)
SELECT
	s.OrderLineID,
	ISNULL(UPPER(LTRIM(RTRIM(l.ItemCode))), '') AS ActualItemCode,
	ISNULL(UPPER(LTRIM(RTRIM(l.ColorCode))), '') AS ActualColorCode,
	ISNULL(UPPER(LTRIM(RTRIM(l.ItemDim2Code))), '') AS ActualDim2Code,
	s.NewItemCode,
	s.NewColor,
	s.NewDim2
FROM src s
JOIN dbo.trOrderLine l
	ON l.OrderLineID = CONVERT(UNIQUEIDENTIFIER, s.OrderLineID)
WHERE l.OrderHeaderID = CONVERT(UNIQUEIDENTIFIER, @p%d)
  AND (
	ISNULL(UPPER(LTRIM(RTRIM(l.ItemCode))), '') <> s.NewItemCode OR
	ISNULL(UPPER(LTRIM(RTRIM(l.ColorCode))), '') <> s.NewColor OR
	ISNULL(UPPER(LTRIM(RTRIM(l.ItemDim2Code))), '') <> s.NewDim2
  );
`, strings.Join(values, ","), orderHeaderParam)

		rows, err := tx.Query(query, args...)
		if err != nil {
			return mismatchCount, samples, err
		}
		for rows.Next() {
			var lineID, actualItem, actualColor, actualDim2, expectedItem, expectedColor, expectedDim2 string
			if err := rows.Scan(&lineID, &actualItem, &actualColor, &actualDim2, &expectedItem, &expectedColor, &expectedDim2); err != nil {
				rows.Close()
				return mismatchCount, samples, err
			}
			mismatchCount++
			if len(samples) < 5 {
				samples = append(samples, fmt.Sprintf(
					"lineID=%s expected=(%s,%s,%s) actual=(%s,%s,%s)",
					lineID, expectedItem, expectedColor, expectedDim2, actualItem, actualColor, actualDim2,
				))
			}
		}
		if err := rows.Err(); err != nil {
			rows.Close()
			return mismatchCount, samples, err
		}
		rows.Close()
	}

	return mismatchCount, samples, nil
}

func UpdateOrderHeaderAverageDueDateTx(tx *sql.Tx, orderHeaderID string, averageDueDate *string, username string) error {
	if averageDueDate == nil {
		return nil
	}

	dueDate := strings.TrimSpace(*averageDueDate)
	if dueDate != "" {
		if _, err := time.Parse("2006-01-02", dueDate); err != nil {
			return fmt.Errorf("invalid header average due date %q: %w", dueDate, err)
		}
	}

	_, err := tx.Exec(`
UPDATE dbo.trOrderHeader
SET
	AverageDueDate = CASE WHEN @p1 = '' THEN NULL ELSE CAST(@p1 AS DATETIME) END,
	LastUpdatedUserName = @p2,
	LastUpdatedDate = GETDATE()
WHERE OrderHeaderID = @p3;
`, dueDate, username, orderHeaderID)
	return err
}

func TouchOrderHeaderTx(tx *sql.Tx, orderHeaderID string, username string) (int64, error) {
	res, err := tx.Exec(`
UPDATE dbo.trOrderHeader
SET
	LastUpdatedUserName = @p1,
	LastUpdatedDate = GETDATE()
WHERE OrderHeaderID = @p2;
`, username, orderHeaderID)
	if err != nil {
		return 0, err
	}
	rows, rowsErr := res.RowsAffected()
	if rowsErr != nil {
		return 0, nil
	}
	return rows, nil
}

type sqlQueryRower interface {
	QueryRow(query string, args ...any) *sql.Row
}

type plannedProductionBarcode struct {
	Barcode         string
	BarcodeTypeCode string
	ItemTypeCode    int16
	ItemCode        string
	ColorCode       string
	ItemDim1Code    string
	ItemDim2Code    string
	ItemDim3Code    string
}

func barcodeTypeExists(q sqlQueryRower, barcodeTypeCode string) (bool, error) {
	var exists int
	err := q.QueryRow(`
SELECT TOP 1 1
FROM dbo.cdBarcodeType
WHERE BarcodeTypeCode = @p1
`, strings.TrimSpace(barcodeTypeCode)).Scan(&exists)
	if err == sql.ErrNoRows {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

func barcodeExists(q sqlQueryRower, barcode string) (bool, error) {
	var exists int
	err := q.QueryRow(`
SELECT TOP 1 1
FROM dbo.prItemBarcode WITH (UPDLOCK, HOLDLOCK)
WHERE Barcode = @p1
`, strings.TrimSpace(barcode)).Scan(&exists)
	if err == sql.ErrNoRows {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

func existingVariantBarcode(
	q sqlQueryRower,
	barcodeTypeCode string,
	itemTypeCode int16,
	itemCode string,
	colorCode string,
	dim1 string,
	dim2 string,
	dim3 string,
) (string, bool, error) {

	var barcode string

	err := q.QueryRow(`
SELECT TOP 1 LTRIM(RTRIM(ISNULL(Barcode, '')))
FROM dbo.prItemBarcode WITH (UPDLOCK, HOLDLOCK)
WHERE BarcodeTypeCode = @p1
  AND ItemTypeCode = @p2
  AND ISNULL(LTRIM(RTRIM(ItemCode)), '') = @p3
  AND ISNULL(LTRIM(RTRIM(ColorCode)), '') = @p4
  AND ISNULL(LTRIM(RTRIM(ItemDim1Code)), '') = @p5
  AND ISNULL(LTRIM(RTRIM(ItemDim2Code)), '') = @p6
  AND ISNULL(LTRIM(RTRIM(ItemDim3Code)), '') = @p7
  AND ISNULL(LTRIM(RTRIM(UnitOfMeasureCode)), '') = 'AD'
ORDER BY
	CASE
		WHEN ISNUMERIC(Barcode) = 1
		THEN CAST(Barcode AS BIGINT)
		ELSE 0
	END DESC,
	Barcode DESC
`,
		strings.TrimSpace(barcodeTypeCode),
		itemTypeCode,
		strings.TrimSpace(itemCode),
		strings.TrimSpace(colorCode),
		strings.TrimSpace(dim1),
		strings.TrimSpace(dim2),
		strings.TrimSpace(dim3),
	).Scan(&barcode)

	if err == sql.ErrNoRows {
		return "", false, nil
	}

	if err != nil {
		return "", false, err
	}

	return strings.TrimSpace(barcode), true, nil
}
func maxNumericBarcode(q sqlQueryRower) (int64, error) {

	var maxBarcode int64

	err := q.QueryRow(`
SELECT ISNULL(MAX(
	CASE
		WHEN ISNUMERIC(Barcode) = 1
		THEN CAST(Barcode AS BIGINT)
		ELSE NULL
	END
), 0)
FROM dbo.prItemBarcode WITH (UPDLOCK, HOLDLOCK)
`).Scan(&maxBarcode)

	return maxBarcode, err
}

func ValidateProductionBarcodePlan(q sqlQueryRower, variants []models.OrderProductionMissingVariant, barcodeTypeCode string) ([]models.OrderProductionBarcodeValidation, error) {
	typeCode := strings.ToUpper(strings.TrimSpace(barcodeTypeCode))
	if len(variants) == 0 {
		return nil, nil
	}

	validations := make([]models.OrderProductionBarcodeValidation, 0)
	typeExists, err := barcodeTypeExists(q, typeCode)
	if err != nil {
		return nil, err
	}
	if !typeExists {
		validations = append(validations, models.OrderProductionBarcodeValidation{
			Code:            "invalid_barcode_type",
			Message:         fmt.Sprintf("Barkod tipi bulunamadi: %s", typeCode),
			BarcodeTypeCode: typeCode,
		})
		return validations, nil
	}

	sorted := append([]models.OrderProductionMissingVariant(nil), variants...)
	sort.Slice(sorted, func(i, j int) bool {
		left := sorted[i]
		right := sorted[j]
		leftKey := fmt.Sprintf("%05d|%s|%s|%s|%s|%s", left.ItemTypeCode, left.ItemCode, left.ColorCode, left.ItemDim1Code, left.ItemDim2Code, left.ItemDim3Code)
		rightKey := fmt.Sprintf("%05d|%s|%s|%s|%s|%s", right.ItemTypeCode, right.ItemCode, right.ColorCode, right.ItemDim1Code, right.ItemDim2Code, right.ItemDim3Code)
		return leftKey < rightKey
	})

	maxBarcode, err := maxNumericBarcode(q)
	if err != nil {
		return nil, err
	}

	nextOffset := int64(0)
	planned := make(map[string]struct{}, len(sorted))
	for _, variant := range sorted {
		existingBarcode, exists, err := existingVariantBarcode(q, typeCode, variant.ItemTypeCode, variant.ItemCode, variant.ColorCode, variant.ItemDim1Code, variant.ItemDim2Code, variant.ItemDim3Code)
		if err != nil {
			return nil, err
		}
		if exists && existingBarcode != "" {
			continue
		}

		nextOffset++
		barcode := strconv.FormatInt(maxBarcode+nextOffset, 10)
		if _, duplicated := planned[barcode]; duplicated {
			validations = append(validations, models.OrderProductionBarcodeValidation{
				Code:            "barcode_duplicate_in_plan",
				Message:         fmt.Sprintf("Planlanan barkod ayni istekte birden fazla kez olusuyor: %s", barcode),
				Barcode:         barcode,
				BarcodeTypeCode: typeCode,
				ItemTypeCode:    variant.ItemTypeCode,
				ItemCode:        strings.TrimSpace(variant.ItemCode),
				ColorCode:       strings.TrimSpace(variant.ColorCode),
				ItemDim1Code:    strings.TrimSpace(variant.ItemDim1Code),
				ItemDim2Code:    strings.TrimSpace(variant.ItemDim2Code),
				ItemDim3Code:    strings.TrimSpace(variant.ItemDim3Code),
			})
			continue
		}
		planned[barcode] = struct{}{}

		inUse, err := barcodeExists(q, barcode)
		if err != nil {
			return nil, err
		}
		if inUse {
			validations = append(validations, models.OrderProductionBarcodeValidation{
				Code:            "barcode_in_use",
				Message:         fmt.Sprintf("Barkod daha once kullanilmis: %s (%s / %s / %s / %s)", barcode, strings.TrimSpace(variant.ItemCode), strings.TrimSpace(variant.ColorCode), strings.TrimSpace(variant.ItemDim1Code), strings.TrimSpace(variant.ItemDim2Code)),
				Barcode:         barcode,
				BarcodeTypeCode: typeCode,
				ItemTypeCode:    variant.ItemTypeCode,
				ItemCode:        strings.TrimSpace(variant.ItemCode),
				ColorCode:       strings.TrimSpace(variant.ColorCode),
				ItemDim1Code:    strings.TrimSpace(variant.ItemDim1Code),
				ItemDim2Code:    strings.TrimSpace(variant.ItemDim2Code),
				ItemDim3Code:    strings.TrimSpace(variant.ItemDim3Code),
			})
		}
	}

	return validations, nil
}

func InsertItemBarcodesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine, username string) (int64, error) {
	start := time.Now()

	if len(lines) == 0 {
		log.Printf("[InsertItemBarcodesTx] lines=0 inserted=0 duration_ms=0")
		return 0, nil
	}

	lineIDs := make([]string, 0, len(lines))
	seen := make(map[string]struct{}, len(lines))

	for _, line := range lines {
		lineID := strings.TrimSpace(line.OrderLineID)
		if lineID == "" {
			continue
		}
		if _, ok := seen[lineID]; ok {
			continue
		}
		seen[lineID] = struct{}{}
		lineIDs = append(lineIDs, lineID)
	}

	if len(lineIDs) == 0 {
		log.Printf("[InsertItemBarcodesTx] uniqueLineIDs=0 inserted=0")
		return 0, nil
	}

	var inserted int64

	singleLineQuery := `
SET NOCOUNT ON;

INSERT INTO dbo.prItemBarcode
(
	Barcode,
	BarcodeTypeCode,
	ItemTypeCode,
	ItemCode,
	ColorCode,
	ItemDim1Code,
	ItemDim2Code,
	ItemDim3Code,
	UnitOfMeasureCode,
	Qty,
	CreatedUserName,
	CreatedDate,
	LastUpdatedUserName,
	LastUpdatedDate,
	RowGuid
)
SELECT
	CAST(seed.MaxBarcode + 1 AS NVARCHAR(50)),
	'BAGGI3',
	src.ItemTypeCode,
	src.ItemCode,
	src.ColorCode,
	src.ItemDim1Code,
	src.ItemDim2Code,
	src.ItemDim3Code,
	'AD',
	1,
	@p3,
	GETDATE(),
	@p3,
	GETDATE(),
	NEWID()
FROM (
	SELECT DISTINCT
		l.ItemTypeCode,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemCode,'')))) AS ItemCode,
		UPPER(LTRIM(RTRIM(ISNULL(l.ColorCode,'')))) AS ColorCode,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim1Code,'')))) AS ItemDim1Code,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim2Code,'')))) AS ItemDim2Code,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim3Code,'')))) AS ItemDim3Code
	FROM dbo.trOrderLine l
	WHERE l.OrderHeaderID = @p2
	  AND CAST(l.OrderLineID AS NVARCHAR(50)) = @p1
	  AND NULLIF(LTRIM(RTRIM(ISNULL(l.ItemCode,''))), '') IS NOT NULL
) src
CROSS JOIN (
	SELECT
		CASE
			WHEN ISNULL(MAX(
				CASE
					WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
						AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
					THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
					ELSE NULL
				END
			), 0) < 36999999
			THEN 36999999
			ELSE ISNULL(MAX(
				CASE
					WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
						AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
					THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
					ELSE NULL
				END
			), 0)
		END AS MaxBarcode
	FROM dbo.prItemBarcode
	WHERE BarcodeTypeCode = 'BAGGI3'
	  AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) <= 8
) seed
WHERE NOT EXISTS (
	SELECT 1
	FROM dbo.prItemBarcode b
	WHERE b.ItemTypeCode = src.ItemTypeCode
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = src.ItemCode
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = src.ColorCode
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = src.ItemDim1Code
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = src.ItemDim2Code
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = src.ItemDim3Code
);
`

	execSingle := func(globalIndex int, lineID string) error {
		lineStart := time.Now()
		res, err := tx.Exec(singleLineQuery, lineID, orderHeaderID, username)
		if err != nil {
			if isDuplicateBarcodeInsertErr(err) {
				log.Printf("[InsertItemBarcodesTx] skip duplicate lineIndex=%d lineID=%s err=%v", globalIndex, lineID, err)
				return nil
			}
			return fmt.Errorf("upsert item barcodes chunk failed chunkStart=%d chunkEnd=%d duration_ms=%d: %w", globalIndex, globalIndex+1, time.Since(lineStart).Milliseconds(), err)
		}
		rows, _ := res.RowsAffected()
		inserted += rows
		log.Printf(
			"[InsertItemBarcodesTx] lineIndex=%d lineID=%s inserted=%d cumulative=%d duration_ms=%d",
			globalIndex,
			lineID,
			rows,
			inserted,
			time.Since(lineStart).Milliseconds(),
		)
		return nil
	}

	const chunkSize = 200
	for i := 0; i < len(lineIDs); i += chunkSize {
		end := i + chunkSize
		if end > len(lineIDs) {
			end = len(lineIDs)
		}

		chunk := lineIDs[i:end]
		values := make([]string, 0, len(chunk))
		args := make([]any, 0, len(chunk)+2)
		paramPos := 1
		for _, lineID := range chunk {
			values = append(values, fmt.Sprintf("(@p%d)", paramPos))
			args = append(args, lineID)
			paramPos++
		}
		orderHeaderParam := paramPos
		usernameParam := paramPos + 1
		args = append(args, orderHeaderID, username)

		batchQuery := fmt.Sprintf(`
SET NOCOUNT ON;

INSERT INTO dbo.prItemBarcode
(
	Barcode,
	BarcodeTypeCode,
	ItemTypeCode,
	ItemCode,
	ColorCode,
	ItemDim1Code,
	ItemDim2Code,
	ItemDim3Code,
	UnitOfMeasureCode,
	Qty,
	CreatedUserName,
	CreatedDate,
	LastUpdatedUserName,
	LastUpdatedDate,
	RowGuid
)
SELECT
	CAST(seed.MaxBarcode + ROW_NUMBER() OVER (
		ORDER BY src.ItemTypeCode, src.ItemCode, src.ColorCode, src.ItemDim1Code, src.ItemDim2Code, src.ItemDim3Code
	) AS NVARCHAR(50)),
	'BAGGI3',
	src.ItemTypeCode,
	src.ItemCode,
	src.ColorCode,
	src.ItemDim1Code,
	src.ItemDim2Code,
	src.ItemDim3Code,
	'AD',
	1,
	@p%d,
	GETDATE(),
	@p%d,
	GETDATE(),
	NEWID()
FROM (
	SELECT DISTINCT
		l.ItemTypeCode,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemCode,'')))) AS ItemCode,
		UPPER(LTRIM(RTRIM(ISNULL(l.ColorCode,'')))) AS ColorCode,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim1Code,'')))) AS ItemDim1Code,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim2Code,'')))) AS ItemDim2Code,
		UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim3Code,'')))) AS ItemDim3Code
	FROM dbo.trOrderLine l
	JOIN (VALUES %s) ids(OrderLineID)
	  ON CAST(l.OrderLineID AS NVARCHAR(50)) = ids.OrderLineID
	WHERE l.OrderHeaderID = @p%d
	  AND NULLIF(LTRIM(RTRIM(ISNULL(l.ItemCode,''))), '') IS NOT NULL
) src
CROSS JOIN (
	SELECT
		CASE
			WHEN ISNULL(MAX(
				CASE
					WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
						AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
					THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
					ELSE NULL
				END
			), 0) < 36999999
			THEN 36999999
			ELSE ISNULL(MAX(
				CASE
					WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
						AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
					THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
					ELSE NULL
				END
			), 0)
		END AS MaxBarcode
	FROM dbo.prItemBarcode
	WHERE BarcodeTypeCode = 'BAGGI3'
	  AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) <= 8
) seed
WHERE NOT EXISTS (
	SELECT 1
	FROM dbo.prItemBarcode b
	WHERE b.ItemTypeCode = src.ItemTypeCode
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = src.ItemCode
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = src.ColorCode
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = src.ItemDim1Code
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = src.ItemDim2Code
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = src.ItemDim3Code
);
`, usernameParam, usernameParam, strings.Join(values, ","), orderHeaderParam)

		chunkStart := time.Now()
		res, err := tx.Exec(batchQuery, args...)
		if err == nil {
			rows, _ := res.RowsAffected()
			inserted += rows
			log.Printf(
				"[InsertItemBarcodesTx] batch=%d-%d inserted=%d cumulative=%d duration_ms=%d",
				i,
				end,
				rows,
				inserted,
				time.Since(chunkStart).Milliseconds(),
			)
			continue
		}

		log.Printf("[InsertItemBarcodesTx] batch fallback=%d-%d err=%v", i, end, err)
		for j, lineID := range chunk {
			if lineErr := execSingle(i+j, lineID); lineErr != nil {
				log.Printf("[InsertItemBarcodesTx] ERROR lineIndex=%d lineID=%s err=%v", i+j, lineID, lineErr)
				return inserted, lineErr
			}
		}
	}

	log.Printf(
		"[InsertItemBarcodesTx] lines=%d unique=%d inserted=%d duration_ms=%d",
		len(lines),
		len(lineIDs),
		inserted,
		time.Since(start).Milliseconds(),
	)

	return inserted, nil
}

func InsertItemBarcodesByTargetsTx(tx *sql.Tx, targets []models.OrderProductionMissingVariant, username string) (int64, error) {
	start := time.Now()
	if len(targets) == 0 {
		log.Printf("[InsertItemBarcodesByTargetsTx] targets=0 inserted=0 duration_ms=0")
		return 0, nil
	}

	uniqueTargets := make([]models.OrderProductionMissingVariant, 0, len(targets))
	seen := make(map[string]struct{}, len(targets))
	for _, t := range targets {
		itemCode := strings.ToUpper(strings.TrimSpace(t.ItemCode))
		if itemCode == "" {
			continue
		}
		key := fmt.Sprintf("%d|%s|%s|%s|%s|%s",
			t.ItemTypeCode,
			itemCode,
			strings.ToUpper(strings.TrimSpace(t.ColorCode)),
			strings.ToUpper(strings.TrimSpace(t.ItemDim1Code)),
			strings.ToUpper(strings.TrimSpace(t.ItemDim2Code)),
			strings.ToUpper(strings.TrimSpace(t.ItemDim3Code)),
		)
		if _, ok := seen[key]; ok {
			continue
		}
		seen[key] = struct{}{}
		t.ItemCode = itemCode
		t.ColorCode = strings.ToUpper(strings.TrimSpace(t.ColorCode))
		t.ItemDim1Code = strings.ToUpper(strings.TrimSpace(t.ItemDim1Code))
		t.ItemDim2Code = strings.ToUpper(strings.TrimSpace(t.ItemDim2Code))
		t.ItemDim3Code = strings.ToUpper(strings.TrimSpace(t.ItemDim3Code))
		uniqueTargets = append(uniqueTargets, t)
	}

	if len(uniqueTargets) == 0 {
		log.Printf("[InsertItemBarcodesByTargetsTx] targets=%d unique=0 inserted=0 duration_ms=%d", len(targets), time.Since(start).Milliseconds())
		return 0, nil
	}
	if err := ensureTxStillActive(tx, "InsertItemBarcodesByTargetsTx/start"); err != nil {
		return 0, err
	}

	// Barcode seed'i hem prItemBarcode hem de (varsa) tbStokBarkodu uzerinden
	// kilitli okuyarak hesapla; trigger tarafindaki duplicate riskini azalt.
	var maxBarcode int64
	maxPrQuery := `
SELECT ISNULL(MAX(v.BarcodeNum), 0)
FROM (
	SELECT
		CASE
			WHEN LTRIM(RTRIM(ISNULL(pb.Barcode,''))) NOT LIKE '%[^0-9]%'
			     AND LEN(LTRIM(RTRIM(ISNULL(pb.Barcode,'')))) BETWEEN 1 AND 18
			THEN CAST(LTRIM(RTRIM(ISNULL(pb.Barcode,''))) AS BIGINT)
			ELSE NULL
		END AS BarcodeNum
	FROM dbo.prItemBarcode pb WITH (UPDLOCK, HOLDLOCK, TABLOCKX)
	WHERE pb.BarcodeTypeCode = 'BAGGI3'
) v
WHERE v.BarcodeNum IS NOT NULL;
`
	if err := tx.QueryRow(maxPrQuery).Scan(&maxBarcode); err != nil {
		return 0, fmt.Errorf("barcode seed query failed: %w", err)
	}
	var hasTb int
	if err := tx.QueryRow(`SELECT CASE WHEN OBJECT_ID(N'dbo.tbStokBarkodu', N'U') IS NULL THEN 0 ELSE 1 END`).Scan(&hasTb); err != nil {
		return 0, fmt.Errorf("barcode seed object check failed: %w", err)
	}
	if hasTb == 1 {
		var maxTb int64
		maxTbQuery := `
SELECT ISNULL(MAX(v.BarcodeNum), 0)
FROM (
	SELECT
		CASE
			WHEN LTRIM(RTRIM(ISNULL(sb.Barcode,''))) NOT LIKE '%[^0-9]%'
			     AND LEN(LTRIM(RTRIM(ISNULL(sb.Barcode,'')))) BETWEEN 1 AND 18
			THEN CAST(LTRIM(RTRIM(ISNULL(sb.Barcode,''))) AS BIGINT)
			ELSE NULL
		END AS BarcodeNum
	FROM dbo.tbStokBarkodu sb WITH (UPDLOCK, HOLDLOCK, TABLOCKX)
) v
WHERE v.BarcodeNum IS NOT NULL;
`
		if err := tx.QueryRow(maxTbQuery).Scan(&maxTb); err != nil {
			return 0, fmt.Errorf("barcode seed tbStokBarkodu query failed: %w", err)
		}
		if maxTb > maxBarcode {
			maxBarcode = maxTb
		}
	}
	if maxBarcode < 36999999 {
		maxBarcode = 36999999
	}
	existsBarcodeQuery := `
SELECT CASE WHEN EXISTS (
	SELECT 1
	FROM dbo.prItemBarcode pb WITH (UPDLOCK, HOLDLOCK)
	WHERE LTRIM(RTRIM(ISNULL(pb.Barcode,''))) = @p1
) THEN 1 ELSE 0 END;
`
	existsBarcodeWithTbQuery := `
SELECT CASE WHEN EXISTS (
	SELECT 1
	FROM dbo.prItemBarcode pb WITH (UPDLOCK, HOLDLOCK)
	WHERE LTRIM(RTRIM(ISNULL(pb.Barcode,''))) = @p1
) OR EXISTS (
	SELECT 1
	FROM dbo.tbStokBarkodu sb WITH (UPDLOCK, HOLDLOCK)
	WHERE LTRIM(RTRIM(ISNULL(sb.Barcode,''))) = @p1
) THEN 1 ELSE 0 END;
`
	hasVariantBarcodeQuery := `
SELECT CASE WHEN EXISTS (
	SELECT 1
	FROM dbo.prItemBarcode b WITH (UPDLOCK, HOLDLOCK)
	WHERE b.ItemTypeCode = @p1
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = @p2
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = @p3
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = @p4
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = @p5
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = @p6
) THEN 1 ELSE 0 END;
`
	insertOneQuery := `
INSERT INTO dbo.prItemBarcode
(
	Barcode,
	BarcodeTypeCode,
	ItemTypeCode,
	ItemCode,
	ColorCode,
	ItemDim1Code,
	ItemDim2Code,
	ItemDim3Code,
	UnitOfMeasureCode,
	Qty,
	CreatedUserName,
	CreatedDate,
	LastUpdatedUserName,
	LastUpdatedDate,
	RowGuid
)
SELECT
	@p1,
	'BAGGI3',
	@p2,
	@p3,
	@p4,
	@p5,
	@p6,
	@p7,
	'AD',
	1,
	@p8,
	GETDATE(),
	@p8,
	GETDATE(),
	NEWID()
WHERE NOT EXISTS (
	SELECT 1
	FROM dbo.prItemBarcode b
	WHERE b.ItemTypeCode = @p2
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = @p3
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = @p4
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = @p5
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = @p6
	  AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = @p7
);
`

	var inserted int64
	for _, t := range uniqueTargets {
		if err := ensureTxStillActive(tx, "InsertItemBarcodesByTargetsTx/before_target"); err != nil {
			return inserted, err
		}
		var hasVariant int
		if err := tx.QueryRow(
			hasVariantBarcodeQuery,
			t.ItemTypeCode,
			t.ItemCode,
			t.ColorCode,
			t.ItemDim1Code,
			t.ItemDim2Code,
			t.ItemDim3Code,
		).Scan(&hasVariant); err != nil {
			return inserted, fmt.Errorf("variant barcode exists check failed: %w", err)
		}
		if hasVariant == 1 {
			continue
		}

		retry := 0
		for {
			retry++
			if retry > 2000 {
				return inserted, fmt.Errorf("barcode allocation exceeded retry limit item=%s color=%s dim1=%s", t.ItemCode, t.ColorCode, t.ItemDim1Code)
			}
			candidateNum := maxBarcode + 1
			candidate := strconv.FormatInt(candidateNum, 10)

			var exists int
			if hasTb == 1 {
				if err := tx.QueryRow(existsBarcodeWithTbQuery, candidate).Scan(&exists); err != nil {
					return inserted, fmt.Errorf("barcode exists check(tb) failed: %w", err)
				}
			} else {
				if err := tx.QueryRow(existsBarcodeQuery, candidate).Scan(&exists); err != nil {
					return inserted, fmt.Errorf("barcode exists check failed: %w", err)
				}
			}
			if exists == 1 {
				maxBarcode = candidateNum
				continue
			}

			res, err := tx.Exec(
				insertOneQuery,
				candidate,
				t.ItemTypeCode,
				t.ItemCode,
				t.ColorCode,
				t.ItemDim1Code,
				t.ItemDim2Code,
				t.ItemDim3Code,
				username,
			)
			if err != nil {
				if isDuplicateBarcodeInsertErr(err) {
					maxBarcode = candidateNum
					continue
				}
				return inserted, fmt.Errorf("insert item barcode failed item=%s color=%s dim1=%s duration_ms=%d: %w",
					t.ItemCode, t.ColorCode, t.ItemDim1Code, time.Since(start).Milliseconds(), err)
			}
			affected, _ := res.RowsAffected()
			if affected > 0 {
				inserted += affected
				maxBarcode = candidateNum
			}
			break
		}
	}

	if txErr := ensureTxStillActive(tx, "InsertItemBarcodesByTargetsTx/after_batch"); txErr != nil {
		return inserted, txErr
	}

	log.Printf("[InsertItemBarcodesByTargetsTx] targets=%d unique=%d inserted=%d duration_ms=%d",
		len(targets), len(uniqueTargets), inserted, time.Since(start).Milliseconds())
	return inserted, nil
}

func ensureTxStillActive(tx *sql.Tx, where string) error {
	if tx == nil {
		return fmt.Errorf("tx is nil at %s", where)
	}
	var tranCount int
	if err := tx.QueryRow(`SELECT @@TRANCOUNT`).Scan(&tranCount); err != nil {
		return fmt.Errorf("tx state query failed at %s: %w", where, err)
	}
	if tranCount <= 0 {
		return fmt.Errorf("tx closed unexpectedly at %s (trancount=%d)", where, tranCount)
	}
	return nil
}

func isDuplicateBarcodeInsertErr(err error) bool {
	if err == nil {
		return false
	}
	msg := strings.ToLower(err.Error())
	if !strings.Contains(msg, "duplicate key") {
		return false
	}
	if strings.Contains(msg, "tbstokbarkodu") {
		return true
	}
	if strings.Contains(msg, "pritembarcode") {
		return true
	}
	return strings.Contains(msg, "unique")
}

func UpsertItemAttributesTx(tx *sql.Tx, attrs []models.OrderProductionItemAttributeRow, username string) (int64, error) {
	start := time.Now()
	if len(attrs) == 0 {
		log.Printf("[UpsertItemAttributesTx] attrs=0 affected=0 duration_ms=0")
		return 0, nil
	}

	// FK_prItemAttribute_ItemCode hatasini engellemek icin, attribute yazmadan once
	// ilgili item kodlarinin cdItem tarafinda varligini transaction icinde garanti et.
	seenCodes := make(map[string]struct{}, len(attrs))
	for _, a := range attrs {
		itemTypeCode := a.ItemTypeCode
		if itemTypeCode <= 0 {
			itemTypeCode = 1
		}
		itemCode := strings.ToUpper(strings.TrimSpace(a.ItemCode))
		if itemCode == "" {
			continue
		}
		key := NormalizeCdItemMapKey(int16(itemTypeCode), itemCode)
		if _, ok := seenCodes[key]; ok {
			continue
		}
		seenCodes[key] = struct{}{}
		if err := ensureCdItemTx(tx, int16(itemTypeCode), itemCode, username, nil); err != nil {
			return 0, fmt.Errorf("ensure cdItem before item attributes failed itemCode=%s: %w", itemCode, err)
		}
	}

	// SQL Server parameter limiti (2100) nedeniyle batch'li set-based upsert kullanilir.
	const chunkSize = 400 // 400 * 4 param + 1 username = 1601
	var affected int64
	for i := 0; i < len(attrs); i += chunkSize {
		end := i + chunkSize
		if end > len(attrs) {
			end = len(attrs)
		}
		chunk := attrs[i:end]

		values := make([]string, 0, len(chunk))
		args := make([]any, 0, len(chunk)*4+1)
		paramPos := 1
		for _, a := range chunk {
			values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3))
			args = append(args, a.ItemTypeCode, a.ItemCode, a.AttributeTypeCode, a.AttributeCode)
			paramPos += 4
		}
		usernameParam := paramPos
		args = append(args, username)

		query := fmt.Sprintf(`
WITH src (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode) AS (
	SELECT *
	FROM (VALUES %s) AS v (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode)
)
UPDATE tgt
SET
	tgt.AttributeCode = src.AttributeCode,
	tgt.LastUpdatedUserName = @p%d,
	tgt.LastUpdatedDate = GETDATE()
FROM dbo.prItemAttribute tgt
JOIN src
	ON src.ItemTypeCode = tgt.ItemTypeCode
	AND src.ItemCode = tgt.ItemCode
	AND src.AttributeTypeCode = tgt.AttributeTypeCode;

WITH src (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode) AS (
	SELECT *
	FROM (VALUES %s) AS v (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode)
)
INSERT INTO dbo.prItemAttribute (
	ItemTypeCode,
	ItemCode,
	AttributeTypeCode,
	AttributeCode,
	CreatedUserName,
	CreatedDate,
	LastUpdatedUserName,
	LastUpdatedDate,
	RowGuid
)
SELECT
	src.ItemTypeCode,
	src.ItemCode,
	src.AttributeTypeCode,
	src.AttributeCode,
	@p%d,
	GETDATE(),
	@p%d,
	GETDATE(),
	NEWID()
FROM src
LEFT JOIN dbo.prItemAttribute tgt
	ON src.ItemTypeCode = tgt.ItemTypeCode
	AND src.ItemCode = tgt.ItemCode
	AND src.AttributeTypeCode = tgt.AttributeTypeCode
WHERE tgt.ItemCode IS NULL;
`, strings.Join(values, ","), usernameParam, strings.Join(values, ","), usernameParam, usernameParam)

		chunkStart := time.Now()
		res, err := tx.Exec(query, args...)
		if err != nil {
			log.Printf("[UpsertItemAttributesTx] ERROR chunk=%d-%d err=%v", i, end, err)
			return affected, fmt.Errorf("upsert item attributes chunk failed chunkStart=%d chunkEnd=%d duration_ms=%d: %w", i, end, time.Since(chunkStart).Milliseconds(), err)
		}
		chunkAffected, _ := res.RowsAffected()
		affected += chunkAffected
		log.Printf("[UpsertItemAttributesTx] chunk=%d-%d chunkAffected=%d cumulative=%d duration_ms=%d",
			i, end, chunkAffected, affected, time.Since(chunkStart).Milliseconds())
	}
	log.Printf("[UpsertItemAttributesTx] attrs=%d affected=%d duration_ms=%d",
		len(attrs), affected, time.Since(start).Milliseconds())
	return affected, nil
}

func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdItemLookups, error) {
	out := models.OrderProductionCdItemLookups{}

	queryPairs := []struct {
		Name   string
		Query  string
		Target *[]models.OrderProductionLookupOption
	}{
		{"ItemDimTypeCodes", `SELECT
			CAST(t.ItemDimTypeCode AS NVARCHAR(50)) AS Code,
			ISNULL(d.ItemDimTypeDescription, CAST(t.ItemDimTypeCode AS NVARCHAR(50))) AS [Description]
		  FROM dbo.bsItemDimType t
		  LEFT JOIN dbo.bsItemDimTypeDesc d
		    ON d.ItemDimTypeCode = t.ItemDimTypeCode
		   AND d.LangCode = 'TR'
		  WHERE ISNULL(t.IsBlocked, 0) = 0
		  ORDER BY t.ItemDimTypeCode`, &out.ItemDimTypeCodes},
		{"ProductTypeCodes", `SELECT DISTINCT CAST(ProductTypeCode AS NVARCHAR(50)) AS Code, CAST(ProductTypeCode AS NVARCHAR(50)) AS [Description] FROM dbo.cdItem WHERE ProductTypeCode IS NOT NULL ORDER BY Code`, &out.ProductTypeCodes},
		{"ProductHierarchyIDs", `SELECT
			CAST(h.ProductHierarchyID AS NVARCHAR(50)) AS Code,
			LTRIM(RTRIM(
				CONCAT(
					CAST(ISNULL(h.ProductHierarchyLevelCode01, 0) AS NVARCHAR(50)),
					CASE
						WHEN ISNULL(d.ProductHierarchyLevelDescription, '') <> '' THEN CONCAT(' - ', d.ProductHierarchyLevelDescription)
						ELSE ''
					END
				)
			)) AS [Description]
		  FROM dbo.dfProductHierarchy h
		  LEFT JOIN dbo.cdProductHierarchyLevelDesc d
		    ON d.ProductHierarchyLevelCode = h.ProductHierarchyLevelCode01
		   AND d.LangCode = 'TR'
		  ORDER BY h.ProductHierarchyID`, &out.ProductHierarchyIDs},
		{"UnitOfMeasureCode1List", `SELECT DISTINCT CAST(UnitOfMeasureCode1 AS NVARCHAR(50)) AS Code, CAST(UnitOfMeasureCode1 AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(UnitOfMeasureCode1 AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.UnitOfMeasureCode1List},
		{"ItemAccountGrCodes", `SELECT DISTINCT CAST(ItemAccountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemAccountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(ItemAccountGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemAccountGrCodes},
		{"ItemTaxGrCodes", `SELECT DISTINCT CAST(ItemTaxGrCode AS NVARCHAR(50)) AS Code, CAST(ItemTaxGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(ItemTaxGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemTaxGrCodes},
		{"ItemPaymentPlanGrCodes", `SELECT DISTINCT CAST(ItemPaymentPlanGrCode AS NVARCHAR(50)) AS Code, CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemPaymentPlanGrCodes},
		{"ItemDiscountGrCodes", `SELECT DISTINCT CAST(ItemDiscountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemDiscountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(ItemDiscountGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemDiscountGrCodes},
		{"ItemVendorGrCodes", `SELECT DISTINCT CAST(ItemVendorGrCode AS NVARCHAR(50)) AS Code, CAST(ItemVendorGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(ItemVendorGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemVendorGrCodes},
		{"PromotionGroupCodes", `SELECT DISTINCT CAST(PromotionGroupCode AS NVARCHAR(50)) AS Code, CAST(PromotionGroupCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(PromotionGroupCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.PromotionGroupCodes},
		{"ProductCollectionGrCodes", `SELECT DISTINCT CAST(ProductCollectionGrCode AS NVARCHAR(50)) AS Code, CAST(ProductCollectionGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(ProductCollectionGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ProductCollectionGrCodes},
		{"StorePriceLevelCodes", `SELECT DISTINCT CAST(StorePriceLevelCode AS NVARCHAR(50)) AS Code, CAST(StorePriceLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(StorePriceLevelCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.StorePriceLevelCodes},
		{"PerceptionOfFashionCodes", `SELECT DISTINCT CAST(PerceptionOfFashionCode AS NVARCHAR(50)) AS Code, CAST(PerceptionOfFashionCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(PerceptionOfFashionCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.PerceptionOfFashionCodes},
		{"CommercialRoleCodes", `SELECT DISTINCT CAST(CommercialRoleCode AS NVARCHAR(50)) AS Code, CAST(CommercialRoleCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(CommercialRoleCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CommercialRoleCodes},
		{"StoreCapacityLevelCodes", `SELECT DISTINCT CAST(StoreCapacityLevelCode AS NVARCHAR(50)) AS Code, CAST(StoreCapacityLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(StoreCapacityLevelCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.StoreCapacityLevelCodes},
		{"CustomsTariffNumbers", `SELECT DISTINCT CAST(CustomsTariffNumberCode AS NVARCHAR(50)) AS Code, CAST(CustomsTariffNumberCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(CustomsTariffNumberCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CustomsTariffNumbers},
		{"CompanyCodes", `SELECT DISTINCT CAST(CompanyCode AS NVARCHAR(50)) AS Code, CAST(CompanyCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WHERE NULLIF(LTRIM(RTRIM(CAST(CompanyCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CompanyCodes},
	}

	for _, pair := range queryPairs {
		start := time.Now()
		log.Printf("[GetOrderProductionLookupOptions] executing [%s]", pair.Name)
		rows, err := mssql.Query(pair.Query)
		if err != nil {
			return out, fmt.Errorf("lookup query failed [%s]: %w", pair.Name, err)
		}

		list := make([]models.OrderProductionLookupOption, 0, 64)
		for rows.Next() {
			var item models.OrderProductionLookupOption
			if err := rows.Scan(&item.Code, &item.Description); err != nil {
				rows.Close()
				return out, fmt.Errorf("lookup scan failed [%s]: %w", pair.Name, err)
			}
			item.Code = strings.TrimSpace(item.Code)
			item.Description = strings.TrimSpace(item.Description)
			list = append(list, item)
		}
		if err := rows.Err(); err != nil {
			rows.Close()
			return out, fmt.Errorf("lookup rows failed [%s]: %w", pair.Name, err)
		}
		rows.Close()
		log.Printf("[GetOrderProductionLookupOptions] ok [%s] count=%d duration=%s", pair.Name, len(list), time.Since(start))
		*pair.Target = list
	}

	return out, nil
}
