package queries

import (
	"bssapp-backend/db"
	"context"
	"database/sql"
	"fmt"
	"strings"
)

// GetProductPricingFilterOptions returns distinct option values for ProductPricing filters.
// This is used to render filter dropdowns without loading the full dataset.
func GetProductPricingFilterOptions(ctx context.Context, field string, q string, limit int, scopeUrunIlkGrubu []string) ([]string, error) {
	pg := db.PgDB
	mssql := db.MssqlDB
	if mssql == nil {
		// Some option fields can still be served from PG cache table.
		if pg == nil {
			return nil, fmt.Errorf("mssql db is nil")
		}
	}
	field = strings.TrimSpace(field)
	q = strings.TrimSpace(q)
	if limit <= 0 || limit > 200 {
		limit = 120
	}
	if len(scopeUrunIlkGrubu) > 3 {
		scopeUrunIlkGrubu = scopeUrunIlkGrubu[:3]
	}

	// Fast path: use PG-derived pricing parameter cache for most fields.
	// This avoids scanning ProductFilterWithDescription('TR') on MSSQL, which can be slow and cause 504s.
	// productCode is not available in mk_urunpricingprmtr, keep MSSQL for that.
	if pg != nil && field != "productCode" {
		pgCol := ""
		switch field {
		case "brandGroupSelection":
			pgCol = "brand_group_sec"
		case "marka":
			pgCol = "marka"
		case "askiliYan":
			pgCol = "askili_yan"
		case "kategori":
			pgCol = "kategori"
		case "urunIlkGrubu":
			pgCol = "urun_ilk_grubu"
		case "urunAnaGrubu":
			pgCol = "urun_ana_grubu"
		case "urunAltGrubu":
			pgCol = "urun_alt_grubu"
		case "icerik":
			pgCol = "icerik"
		case "karisim":
			// "karisim" is intentionally deprecated in mk_urunpricingprmtr, keep MSSQL fallback.
			pgCol = ""
		default:
			pgCol = ""
		}

		if pgCol != "" {
			args := make([]any, 0, 8)
			where := []string{
				"is_active = TRUE",
				fmt.Sprintf("NULLIF(BTRIM(%s), '') IS NOT NULL", pgCol),
			}
			if len(scopeUrunIlkGrubu) > 0 && field != "urunIlkGrubu" {
				args = append(args, scopeUrunIlkGrubu)
				where = append(where, fmt.Sprintf("urun_ilk_grubu = ANY($%d::text[])", len(args)))
			}
			if q != "" {
				like := q + "%"
				args = append(args, like)
				where = append(where, fmt.Sprintf("%s ILIKE $%d", pgCol, len(args)))
			}
			whereSQL := strings.Join(where, " AND ")

			// Note: DISTINCT+ORDER+LIMIT is fine here due to small mk_urunpricingprmtr cardinality (~1000 rows).
			sqlText := fmt.Sprintf(`
SELECT DISTINCT %s AS val
FROM mk_urunpricingprmtr
WHERE %s
ORDER BY val ASC
LIMIT %d
`, pgCol, whereSQL, limit)

			rows, err := pg.QueryContext(ctx, sqlText, args...)
			if err == nil {
				defer rows.Close()
				out := make([]string, 0, limit)
				for rows.Next() {
					var v sql.NullString
					if err := rows.Scan(&v); err != nil {
						return nil, err
					}
					if s := strings.TrimSpace(v.String); s != "" {
						out = append(out, s)
					}
				}
				if err := rows.Err(); err != nil {
					return nil, err
				}
				return out, nil
			}
			// If PG path fails, fall back to MSSQL below.
		}
	}

	// Map UI filter fields -> MSSQL expression in ProductFilterWithDescription('TR')
	var expr string
	switch field {
	case "productCode":
		expr = "LTRIM(RTRIM(ProductCode))"
	case "brandGroupSelection":
		expr = `CASE ABS(CHECKSUM(LTRIM(RTRIM(ProductCode)))) % 3 
			WHEN 0 THEN 'MARKA GRUBU A' 
			WHEN 1 THEN 'MARKA GRUBU B' 
			ELSE 'MARKA GRUBU C' 
		END`
	case "marka":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt10Desc)), '')"
	case "askiliYan":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt45Desc)), '')"
	case "kategori":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt44Desc)), '')"
	case "urunIlkGrubu":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt42Desc)), '')"
	case "urunAnaGrubu":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt01Desc)), '')"
	case "urunAltGrubu":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt02Desc)), '')"
	case "icerik":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt41Desc)), '')"
	case "karisim":
		expr = "COALESCE(LTRIM(RTRIM(ProductAtt29Desc)), '')"
	default:
		return nil, fmt.Errorf("invalid field")
	}

	// NOTE: We keep the same base constraints as the listing query.
	// q: prefix match to keep it sargable-ish.
	args := make([]any, 0, 8)
	where := []string{
		"ProductAtt42 IN ('SERI', 'AKSESUAR')",
		"IsBlocked = 0",
		"LEN(LTRIM(RTRIM(ProductCode))) = 13",
	}
	if len(scopeUrunIlkGrubu) > 0 && field != "urunIlkGrubu" {
		// Cascade scope: allow limiting options by the already selected "Urun Ilk Grubu" (desc).
		// We filter by desc value because UI uses desc fields.
		placeholders := make([]string, 0, len(scopeUrunIlkGrubu))
		for _, v := range scopeUrunIlkGrubu {
			v = strings.TrimSpace(v)
			if v == "" {
				continue
			}
			placeholders = append(placeholders, fmt.Sprintf("@p%d", len(args)+1))
			args = append(args, v)
		}
		if len(placeholders) > 0 {
			where = append(where, fmt.Sprintf("COALESCE(LTRIM(RTRIM(ProductAtt42Desc)), '') IN (%s)", strings.Join(placeholders, ", ")))
		}
	}
	if q != "" {
		// For productCode, allow contains if user types middle; for others use prefix.
		if field == "productCode" {
			where = append(where, expr+fmt.Sprintf(" LIKE @p%d", len(args)+1))
			args = append(args, "%"+q+"%")
		} else {
			where = append(where, expr+fmt.Sprintf(" LIKE @p%d", len(args)+1))
			args = append(args, q+"%")
		}
	}
	whereSQL := strings.Join(where, " AND ")

	sqlText := fmt.Sprintf(`
SELECT TOP (%d)
  X.val
FROM (
  SELECT DISTINCT NULLIF(%s, '') AS val
  FROM ProductFilterWithDescription('TR')
  WHERE %s
) X
WHERE X.val IS NOT NULL
ORDER BY X.val ASC;
`, limit, expr, whereSQL)

	rows, err := mssql.QueryContext(ctx, sqlText, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	out := make([]string, 0, limit)
	for rows.Next() {
		var v sql.NullString
		if err := rows.Scan(&v); err != nil {
			return nil, err
		}
		if s := strings.TrimSpace(v.String); s != "" {
			out = append(out, s)
		}
	}
	return out, rows.Err()
}
