package queries

import (
	"bssapp-backend/db"
	"bssapp-backend/models"
	"database/sql"
	"errors"
	"fmt"
)

// GetOrderByID returns order header and lines.
func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, error) {
	conn := db.GetDB()

	logger.Printf("[GetOrderByID] begin id=%s", orderID)

	var header models.OrderHeader
	qHeader := `
	SELECT
		CAST(h.OrderHeaderID AS varchar(36)) AS OrderHeaderID,
		h.OrderTypeCode,
		h.ProcessCode,
		h.OrderNumber,
		h.IsCancelOrder,
		h.OrderDate,
		h.OrderTime,
		h.DocumentNumber,
		h.PaymentTerm,
		h.AverageDueDate,
		h.Description,
		h.InternalDescription,
		h.CurrAccTypeCode,
		h.CurrAccCode,
		d.CurrAccDescription,
		h.SubCurrAccID,
		h.ContactID,
		h.ShipmentMethodCode,
		h.ShippingPostalAddressID,
		h.BillingPostalAddressID,
		h.GuarantorContactID,
		h.GuarantorContactID2,
		h.RoundsmanCode,
		h.DeliveryCompanyCode,
		h.TaxTypeCode,
		h.WithHoldingTaxTypeCode,
		h.DOVCode,
		h.TaxExemptionCode,
		h.CompanyCode,
		h.OfficeCode,
		h.StoreTypeCode,
		h.StoreCode,
		h.POSTerminalID,
		h.WarehouseCode,
		h.ToWarehouseCode,
		h.OrdererCompanyCode,
		h.OrdererOfficeCode,
		h.OrdererStoreCode,
		h.GLTypeCode,
		h.DocCurrencyCode,
		h.LocalCurrencyCode,
		h.ExchangeRate,
		h.TDisRate1,
		h.TDisRate2,
		h.TDisRate3,
		h.TDisRate4,
		h.TDisRate5,
		h.DiscountReasonCode,
		h.SurplusOrderQtyToleranceRate,
		h.ImportFileNumber,
		h.ExportFileNumber,
		h.IncotermCode1,
		h.IncotermCode2,
		h.LettersOfCreditNumber,
		h.PaymentMethodCode,
		h.IsInclutedVat,
		h.IsCreditSale,
		h.IsCreditableConfirmed,
		h.CreditableConfirmedUser,
		h.CreditableConfirmedDate,
		h.IsSalesViaInternet,
		h.IsSuspended,
		h.IsCompleted,
		h.IsPrinted,
		h.IsLocked,
		h.UserLocked,
		h.IsClosed,
		h.ApplicationCode,
		h.ApplicationID,
		h.CreatedUserName,
		h.CreatedDate,
		h.LastUpdatedUserName,
		h.LastUpdatedDate,
		h.IsProposalBased
	FROM BAGGI_V3.dbo.trOrderHeader AS h
	LEFT JOIN BAGGI_V3.dbo.cdCurrAccDesc AS d
		ON h.CurrAccCode = d.CurrAccCode
	WHERE h.OrderHeaderID = @p1;
	`

	err := conn.QueryRow(qHeader, orderID).Scan(
		&header.OrderHeaderID,
		&header.OrderTypeCode,
		&header.ProcessCode,
		&header.OrderNumber,
		&header.IsCancelOrder,
		&header.OrderDate,
		&header.OrderTime,
		&header.DocumentNumber,
		&header.PaymentTerm,
		&header.AverageDueDate,
		&header.Description,
		&header.InternalDescription,
		&header.CurrAccTypeCode,
		&header.CurrAccCode,
		&header.CurrAccDescription,
		&header.SubCurrAccID,
		&header.ContactID,
		&header.ShipmentMethodCode,
		&header.ShippingPostalAddressID,
		&header.BillingPostalAddressID,
		&header.GuarantorContactID,
		&header.GuarantorContactID2,
		&header.RoundsmanCode,
		&header.DeliveryCompanyCode,
		&header.TaxTypeCode,
		&header.WithHoldingTaxTypeCode,
		&header.DOVCode,
		&header.TaxExemptionCode,
		&header.CompanyCode,
		&header.OfficeCode,
		&header.StoreTypeCode,
		&header.StoreCode,
		&header.POSTerminalID,
		&header.WarehouseCode,
		&header.ToWarehouseCode,
		&header.OrdererCompanyCode,
		&header.OrdererOfficeCode,
		&header.OrdererStoreCode,
		&header.GLTypeCode,
		&header.DocCurrencyCode,
		&header.LocalCurrencyCode,
		&header.ExchangeRate,
		&header.TDisRate1,
		&header.TDisRate2,
		&header.TDisRate3,
		&header.TDisRate4,
		&header.TDisRate5,
		&header.DiscountReasonCode,
		&header.SurplusOrderQtyToleranceRate,
		&header.ImportFileNumber,
		&header.ExportFileNumber,
		&header.IncotermCode1,
		&header.IncotermCode2,
		&header.LettersOfCreditNumber,
		&header.PaymentMethodCode,
		&header.IsInclutedVat,
		&header.IsCreditSale,
		&header.IsCreditableConfirmed,
		&header.CreditableConfirmedUser,
		&header.CreditableConfirmedDate,
		&header.IsSalesViaInternet,
		&header.IsSuspended,
		&header.IsCompleted,
		&header.IsPrinted,
		&header.IsLocked,
		&header.UserLocked,
		&header.IsClosed,
		&header.ApplicationCode,
		&header.ApplicationID,
		&header.CreatedUserName,
		&header.CreatedDate,
		&header.LastUpdatedUserName,
		&header.LastUpdatedDate,
		&header.IsProposalBased,
	)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			logger.Printf("[GetOrderByID] not found: %s", orderID)
			return nil, nil, sql.ErrNoRows
		}
		logger.Printf("[GetOrderByID] header error: %v", err)
		return nil, nil, err
	}

	qLines := `
SELECT
	CAST(L.OrderLineID AS varchar(36)) AS OrderLineID,
	L.SortOrder,
	L.ItemTypeCode,
	L.ItemCode,
	L.ColorCode,
	L.ItemDim1Code,
	L.ItemDim2Code,
	L.ItemDim3Code,
	L.Qty1,
	L.Qty2,

	ISNULL(CD.Price, 0) AS Price,
	ISNULL(CD.CurrencyCode, ISNULL(L.DocCurrencyCode, 'TRY')) AS DocCurrencyCode,
	ISNULL(CD.RelationCurrencyCode, ISNULL(L.DocCurrencyCode, 'TRY')) AS RelationCurrencyCode,
	ISNULL(CD.ExchangeRate, ISNULL(L.PriceExchangeRate, 1)) AS PriceExchangeRate,
	ISNULL(CD.PriceVI, ISNULL(L.Price, 0)) AS DocPrice,
	ISNULL(CD.AmountVI, ISNULL(L.Price, 0) * ISNULL(L.Qty1, 0)) AS DocAmount,
	ISNULL(CD.LDiscount1, 0) AS LineDiscount,
	ISNULL(CD.TDiscount1, 0) AS TotalDiscount,
	ISNULL(CD.TaxBase, 0) AS TaxBase,
	ISNULL(CD.Pct, 0) AS Pct,
	ISNULL(CD.Vat, 0) AS VatAmount,
	ISNULL(CD.VatDeducation, 0) AS VatDeducation,
	ISNULL(CD.NetAmount, 0) AS NetAmount,
	ISNULL(CL.Price, ISNULL(CD.Price, 0)) AS LocalPrice,
	ISNULL(CL.Amount, ISNULL(CD.Amount, 0)) AS LocalAmount,

	L.VatRate,
	L.PCTRate,
	L.DeliveryDate,
	L.PlannedDateOfLading,
	L.LineDescription,
	CASE
		WHEN ISNULL(L.IsClosed, 0) = 1
			OR EXISTS (
				SELECT 1
				FROM BAGGI_V3.dbo.trInvoiceLine il
				WHERE il.OrderLineID = L.OrderLineID
			)
			THEN CAST(1 AS bit)
		ELSE CAST(0 AS bit)
	END AS IsClosed,
	L.CreatedUserName,
	L.CreatedDate,
	L.LastUpdatedUserName,
	L.LastUpdatedDate,

	P.ProductAtt42Desc AS UrunIlkGrubu,
	P.ProductAtt01Desc AS UrunAnaGrubu,
	P.ProductAtt02Desc AS UrunAltGrubu,
	P.ProductAtt38Desc AS Fit1,
	P.ProductAtt39Desc AS Fit2
FROM BAGGI_V3.dbo.trOrderLine AS L
LEFT JOIN BAGGI_V3.dbo.trOrderLineCurrency AS CD
	ON CD.OrderLineID = L.OrderLineID
	AND CD.CurrencyCode = ISNULL(NULLIF(LTRIM(RTRIM(L.DocCurrencyCode)), ''), 'TRY')
LEFT JOIN BAGGI_V3.dbo.trOrderLineCurrency AS CL
	ON CL.OrderLineID = L.OrderLineID
	AND CL.CurrencyCode = 'TRY'
LEFT JOIN ProductFilterWithDescription('TR') AS P
	ON LTRIM(RTRIM(P.ProductCode)) = LTRIM(RTRIM(L.ItemCode))
WHERE L.OrderHeaderID = @p1
ORDER BY L.SortOrder ASC;
`

	rows, err := conn.Query(qLines, orderID)
	if err != nil {
		logger.Printf("[GetOrderByID] lines error: %v", err)
		return &header, nil, err
	}
	defer rows.Close()

	lines := make([]models.OrderDetail, 0, 32)
	for rows.Next() {
		var ln models.OrderDetail
		if err := rows.Scan(
			&ln.OrderLineID,
			&ln.SortOrder,
			&ln.ItemTypeCode,
			&ln.ItemCode,
			&ln.ColorCode,
			&ln.ItemDim1Code,
			&ln.ItemDim2Code,
			&ln.ItemDim3Code,
			&ln.Qty1,
			&ln.Qty2,
			&ln.Price,
			&ln.DocCurrencyCode,
			&ln.RelationCurrencyCode,
			&ln.PriceExchangeRate,
			&ln.DocPrice,
			&ln.DocAmount,
			&ln.LineDiscount,
			&ln.TotalDiscount,
			&ln.TaxBase,
			&ln.Pct,
			&ln.VatAmount,
			&ln.VatDeducation,
			&ln.NetAmount,
			&ln.LocalPrice,
			&ln.LocalAmount,
			&ln.VatRate,
			&ln.PCTRate,
			&ln.DeliveryDate,
			&ln.PlannedDateOfLading,
			&ln.LineDescription,
			&ln.IsClosed,
			&ln.CreatedUserName,
			&ln.CreatedDate,
			&ln.LastUpdatedUserName,
			&ln.LastUpdatedDate,
			&ln.UrunIlkGrubu,
			&ln.UrunAnaGrubu,
			&ln.UrunAltGrubu,
			&ln.Fit1,
			&ln.Fit2,
		); err != nil {
			return &header, nil, fmt.Errorf("line scan error: %w", err)
		}
		lines = append(lines, ln)
	}
	if err := rows.Err(); err != nil {
		return &header, nil, fmt.Errorf("line rows error: %w", err)
	}

	logger.Printf("[GetOrderByID] lines loaded count=%d", len(lines))
	return &header, lines, nil
}
