package routes

import (
	"bssapp-backend/db"
	"bssapp-backend/queries"
	"context"
	"encoding/json"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const filterValueSeparator = "\x1f"

type stockAttrFilters struct {
	kategori     string
	urunAnaGrubu string
	urunAltGrubu []string
	renk         []string
	renk2        []string
	urunIcerigi  []string
	fit          []string
	drop         []string
	beden        []string
}

func readStockAttrFilters(r *http.Request) stockAttrFilters {
	q := r.URL.Query()

	return stockAttrFilters{
		kategori:     readSingleFilter(q, "kategori", "att44"),
		urunAnaGrubu: readSingleFilter(q, "urun_ana_grubu", "att01"),
		urunAltGrubu: readMultiFilter(q, "urun_alt_grubu", "att02"),
		renk:         readMultiFilter(q, "renk"),
		renk2:        readMultiFilter(q, "renk2", "yaka"),
		urunIcerigi:  readMultiFilter(q, "urun_icerigi", "att41"),
		fit:          readMultiFilter(q, "fit", "att38"),
		drop:         readMultiFilter(q, "drop", "att11"),
		beden:        readMultiFilter(q, "beden"),
	}
}

func firstNonEmpty(vals ...string) string {
	for _, v := range vals {
		if strings.TrimSpace(v) != "" {
			return v
		}
	}
	return ""
}

func readSingleFilter(q url.Values, keys ...string) string {
	for _, k := range keys {
		for _, raw := range q[k] {
			if v := strings.TrimSpace(raw); v != "" {
				return v
			}
		}
	}
	return ""
}

func splitFilterToken(raw string) []string {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return nil
	}
	r := strings.NewReplacer(
		filterValueSeparator, ",",
		";", ",",
	)
	normalized := r.Replace(raw)
	parts := strings.Split(normalized, ",")
	out := make([]string, 0, len(parts))
	for _, p := range parts {
		v := strings.TrimSpace(p)
		if v != "" {
			out = append(out, v)
		}
	}
	return out
}

func readMultiFilter(q url.Values, keys ...string) []string {
	seen := make(map[string]struct{}, 8)
	out := make([]string, 0, 8)
	for _, k := range keys {
		for _, raw := range q[k] {
			for _, token := range splitFilterToken(raw) {
				if _, ok := seen[token]; ok {
					continue
				}
				seen[token] = struct{}{}
				out = append(out, token)
			}
		}
	}
	return out
}

func joinFilterValues(values []string) string {
	if len(values) == 0 {
		return ""
	}
	return strings.Join(values, filterValueSeparator)
}

// GetProductStockAttributeOptionsHandler
// GET /api/product-stock-attribute-options
func GetProductStockAttributeOptionsHandler(w http.ResponseWriter, r *http.Request) {
	f := readStockAttrFilters(r)

	ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
	defer cancel()

	rows, err := db.MssqlDB.QueryContext(
		ctx,
		queries.GetProductStockAttributeOptionsQuery,
		f.kategori,
		f.urunAnaGrubu,
		joinFilterValues(f.urunAltGrubu),
		joinFilterValues(f.renk),
		joinFilterValues(f.renk2),
		joinFilterValues(f.urunIcerigi),
		joinFilterValues(f.fit),
		joinFilterValues(f.drop),
		joinFilterValues(f.beden),
	)
	if err != nil {
		log.Printf("[PRODUCT-STOCK-ATTR-OPTIONS] SQL hatasi: %v", err)
		http.Error(w, "SQL hatasi: "+err.Error(), http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	result := map[string][]string{
		"kategori":       {},
		"urun_ana_grubu": {},
		"urun_alt_grubu": {},
		"renk":           {},
		"renk2":          {},
		"urun_icerigi":   {},
		"fit":            {},
		"drop":           {},
		"beden":          {},
	}

	for rows.Next() {
		var fieldName, fieldValue string
		if err := rows.Scan(&fieldName, &fieldValue); err != nil {
			continue
		}
		fieldName = strings.TrimSpace(fieldName)
		fieldValue = strings.TrimSpace(fieldValue)
		if fieldName == "" || fieldValue == "" {
			continue
		}
		result[fieldName] = append(result[fieldName], fieldValue)
	}

	if err := rows.Err(); err != nil {
		http.Error(w, "Satir okuma hatasi: "+err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	_ = json.NewEncoder(w).Encode(result)
}

// GetProductStockQueryByAttributesHandler
// GET /api/product-stock-query-by-attributes
func GetProductStockQueryByAttributesHandler(w http.ResponseWriter, r *http.Request) {
	f := readStockAttrFilters(r)

	if f.kategori == "" || f.urunAnaGrubu == "" {
		http.Error(w, "Kategori ve Urun Ana Grubu secimi zorunludur", http.StatusBadRequest)
		return
	}

	start := time.Now()
	ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
	defer cancel()
	log.Printf(
		"[PRODUCT-STOCK-BY-ATTRS] request kategori=%q urun_ana_grubu=%q urun_alt_grubu=%q renk=%q renk2=%q urun_icerigi=%q fit=%q drop=%q beden=%q",
		f.kategori, f.urunAnaGrubu, strings.Join(f.urunAltGrubu, ","), strings.Join(f.renk, ","), strings.Join(f.renk2, ","), strings.Join(f.urunIcerigi, ","), strings.Join(f.fit, ","), strings.Join(f.drop, ","), strings.Join(f.beden, ","),
	)

	rows, err := db.MssqlDB.QueryContext(
		ctx,
		queries.GetProductStockQueryByAttributes,
		f.kategori,
		f.urunAnaGrubu,
		joinFilterValues(f.urunAltGrubu),
		joinFilterValues(f.renk),
		joinFilterValues(f.renk2),
		joinFilterValues(f.urunIcerigi),
		joinFilterValues(f.fit),
		joinFilterValues(f.drop),
		joinFilterValues(f.beden),
	)
	if err != nil {
		log.Printf("[PRODUCT-STOCK-BY-ATTRS] SQL hatasi: %v", err)
		http.Error(w, "SQL hatasi: "+err.Error(), http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	columns, err := rows.Columns()
	if err != nil {
		http.Error(w, "Kolon bilgisi alinamadi", http.StatusInternalServerError)
		return
	}

	result := make([]map[string]interface{}, 0, 256)
	for rows.Next() {
		raw := make([]interface{}, len(columns))
		dest := make([]interface{}, len(columns))
		for i := range raw {
			dest[i] = &raw[i]
		}
		if err := rows.Scan(dest...); err != nil {
			continue
		}

		rowMap := make(map[string]interface{}, len(columns))
		for i, c := range columns {
			rowMap[c] = normalizeSQLValue(raw[i])
		}
		result = append(result, rowMap)
	}

	if err := rows.Err(); err != nil {
		log.Printf("[PRODUCT-STOCK-BY-ATTRS] rows err elapsed=%s err=%v", time.Since(start), err)
		http.Error(w, "Satir okuma hatasi: "+err.Error(), http.StatusInternalServerError)
		return
	}
	log.Printf("[PRODUCT-STOCK-BY-ATTRS] success rows=%d elapsed=%s", len(result), time.Since(start))

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	_ = json.NewEncoder(w).Encode(result)
}
