package routes

import (
	"bssapp-backend/queries"
	"bssapp-backend/utils"
	"context"
	"database/sql"
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func GetProductPerformanceHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		f := queries.ProductPerformanceFilters{
			Search:      strings.TrimSpace(r.URL.Query().Get("q")),
			ProductCode: strings.TrimSpace(r.URL.Query().Get("product_code")),
			MarketKey:   strings.TrimSpace(r.URL.Query().Get("market_key")),
			Kategori:    strings.TrimSpace(r.URL.Query().Get("kategori")),
			Seri:        strings.TrimSpace(r.URL.Query().Get("seri")),
			Bucket:      strings.TrimSpace(r.URL.Query().Get("bucket")),
			SortBy:      strings.TrimSpace(r.URL.Query().Get("sort_by")),
			Descending:  boolQuery(r, "descending", true),
			Limit:       intQuery(r, "limit", 50000),
			Page:        intQuery(r, "page", 1),
		}
		rows, total, err := queries.ListProductPerformance(ctx, pg, f)
		if err != nil {
			http.Error(w, "urun performans listesi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("X-Total-Count", strconv.Itoa(total))
		_ = json.NewEncoder(w).Encode(map[string]any{
			"rows":        rows,
			"total_count": total,
			"page":        f.Page,
			"limit":       f.Limit,
		})
	}
}

func GetProductPerformanceSalesDetailsHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
		defer cancel()
		rows, err := queries.ListProductPerformanceSalesDetails(
			ctx,
			pg,
			strings.TrimSpace(r.URL.Query().Get("product_code")),
			strings.TrimSpace(r.URL.Query().Get("color_code")),
			strings.TrimSpace(r.URL.Query().Get("yaka_kodu")),
			intQuery(r, "limit", 100),
		)
		if err != nil {
			http.Error(w, "urun satis detayi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceStockSizesHandler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second)
		defer cancel()
		rows, err := queries.ListProductPerformanceStockSizes(
			ctx,
			strings.TrimSpace(r.URL.Query().Get("product_code")),
			strings.TrimSpace(r.URL.Query().Get("color_code")),
			strings.TrimSpace(r.URL.Query().Get("yaka_kodu")),
		)
		if err != nil {
			http.Error(w, "urun beden stok detayi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceSummaryHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		summary, err := queries.GetProductPerformanceSummary(ctx, pg)
		if err != nil {
			http.Error(w, "urun performans ozeti alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(summary)
	}
}

func GetProductPerformanceGeneralHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceGeneral(ctx, pg, intQuery(r, "limit", 50000))
		if err != nil {
			http.Error(w, "genel urun performans KPI alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceOrdersHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceOrderAnalysis(ctx, pg, intQuery(r, "limit", 50000))
		if err != nil {
			http.Error(w, "siparis analiz verisi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceOrderGroupsHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceOrderGroups(
			ctx,
			pg,
			strings.TrimSpace(r.URL.Query().Get("breakdown")),
			intQuery(r, "limit", 50000),
		)
		if err != nil {
			http.Error(w, "siparis grup analiz verisi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceOrderProductCustomersHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceOrderProductCustomers(ctx, pg, intQuery(r, "limit", 50000))
		if err != nil {
			http.Error(w, "urun musteri siparis analiz verisi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceOrderMarketDetailsHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceOrderMarketDetails(ctx, pg, intQuery(r, "limit", 50000))
		if err != nil {
			http.Error(w, "piyasa siparis detay analiz verisi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceMarketsHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceMarkets(ctx, pg, intQuery(r, "limit", 50000))
		if err != nil {
			http.Error(w, "piyasa performans ozeti alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceCountriesHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceCountries(ctx, pg, intQuery(r, "limit", 50000))
		if err != nil {
			http.Error(w, "ulke performans ozeti alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceCustomersHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceCustomers(
			ctx,
			pg,
			strings.TrimSpace(r.URL.Query().Get("breakdown")),
			intQuery(r, "limit", 50000),
		)
		if err != nil {
			http.Error(w, "musteri performans kirilimi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceSalesBreakdownHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		rows, err := queries.ListProductPerformanceSalesBreakdown(
			ctx,
			pg,
			strings.TrimSpace(r.URL.Query().Get("mode")),
			intQuery(r, "limit", 50000),
		)
		if err != nil {
			http.Error(w, "satis kpi kirilimi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceGroupedHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 180*time.Second)
		defer cancel()

		mode := strings.TrimSpace(r.URL.Query().Get("mode"))
		mainGroup := strings.TrimSpace(r.URL.Query().Get("urun_ana_grubu"))
		sortBy := strings.TrimSpace(r.URL.Query().Get("sort_by"))
		descending := boolQuery(r, "descending", true)
		groupLevels := splitCSVQuery(r.URL.Query().Get("group_levels"))
		limit := intQuery(r, "limit", 50000)
		expanded := map[string]bool{}
		filters := map[string][]string{}
		expandThroughLevel := -1
		if rawExpandLevel := strings.TrimSpace(r.URL.Query().Get("expand_through_level")); rawExpandLevel != "" {
			if parsed, err := strconv.Atoi(rawExpandLevel); err == nil {
				expandThroughLevel = parsed
			}
		}
		const maxExpandedGroupKeys = 1000
		addExpandedKey := func(key string) {
			key = strings.TrimSpace(key)
			if key != "" && len(expanded) < maxExpandedGroupKeys {
				expanded[key] = true
			}
		}
		if r.Method == http.MethodPost {
			var body struct {
				Mode               string              `json:"mode"`
				GroupLevels        []string            `json:"group_levels"`
				ExpandedKeys       []string            `json:"expanded_keys"`
				ExpandThroughLevel *int                `json:"expand_through_level"`
				Limit              int                 `json:"limit"`
				MainGroup          string              `json:"urun_ana_grubu"`
				Filters            map[string][]string `json:"filters"`
				SortBy             string              `json:"sort_by"`
				Descending         *bool               `json:"descending"`
			}
			if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
				http.Error(w, "gecersiz grup istegi: "+err.Error(), http.StatusBadRequest)
				return
			}
			if strings.TrimSpace(body.Mode) != "" {
				mode = strings.TrimSpace(body.Mode)
			}
			if strings.TrimSpace(body.MainGroup) != "" {
				mainGroup = strings.TrimSpace(body.MainGroup)
			}
			if len(body.GroupLevels) > 0 {
				groupLevels = body.GroupLevels
			}
			if body.Limit > 0 {
				limit = body.Limit
			}
			for _, key := range body.ExpandedKeys {
				addExpandedKey(key)
			}
			if body.ExpandThroughLevel != nil {
				expandThroughLevel = *body.ExpandThroughLevel
			}
			if len(body.Filters) > 0 {
				filters = body.Filters
			}
			if strings.TrimSpace(body.SortBy) != "" {
				sortBy = strings.TrimSpace(body.SortBy)
			}
			if body.Descending != nil {
				descending = *body.Descending
			}
		} else {
			for _, key := range strings.Split(r.URL.Query().Get("expanded_keys"), ",") {
				addExpandedKey(key)
			}
		}

		rows, err := queries.ListProductPerformanceGrouped(ctx, pg, queries.ProductPerformanceGroupedRequest{
			Mode:               mode,
			GroupLevels:        groupLevels,
			ExpandedKeys:       expanded,
			ExpandThroughLevel: expandThroughLevel,
			Limit:              limit,
			MainGroup:          mainGroup,
			Filters:            filters,
			SortBy:             sortBy,
			Descending:         descending,
		})
		if err != nil {
			log.Printf("[ProductPerformance][grouped] failed trace_id=%s mode=%s levels=%v expand_through_level=%d filters=%d: %v", traceID, mode, groupLevels, expandThroughLevel, len(filters), err)
			http.Error(w, "urun performans grup verisi alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(rows)
	}
}

func GetProductPerformanceGroupedFilterOptionsHandler(pg *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		traceID := utils.TraceIDFromRequest(r)
		ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 60*time.Second)
		defer cancel()

		mode := strings.TrimSpace(r.URL.Query().Get("mode"))
		mainGroup := strings.TrimSpace(r.URL.Query().Get("urun_ana_grubu"))
		groupLevels := splitCSVQuery(r.URL.Query().Get("group_levels"))
		fields := splitCSVQuery(r.URL.Query().Get("fields"))
		limit := intQuery(r, "limit", 50000)

		if r.Method == http.MethodPost {
			var body struct {
				Mode        string   `json:"mode"`
				GroupLevels []string `json:"group_levels"`
				MainGroup   string   `json:"urun_ana_grubu"`
				Fields      []string `json:"fields"`
				Limit       int      `json:"limit"`
			}
			if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
				http.Error(w, "gecersiz filtre secenek istegi: "+err.Error(), http.StatusBadRequest)
				return
			}
			if strings.TrimSpace(body.Mode) != "" {
				mode = strings.TrimSpace(body.Mode)
			}
			if strings.TrimSpace(body.MainGroup) != "" {
				mainGroup = strings.TrimSpace(body.MainGroup)
			}
			if len(body.GroupLevels) > 0 {
				groupLevels = body.GroupLevels
			}
			if len(body.Fields) > 0 {
				fields = body.Fields
			}
			if body.Limit > 0 {
				limit = body.Limit
			}
		}

		options, err := queries.ListProductPerformanceGroupedFilterOptions(ctx, pg, queries.ProductPerformanceGroupedFilterOptionsRequest{
			Mode:        mode,
			GroupLevels: groupLevels,
			MainGroup:   mainGroup,
			Fields:      fields,
			Limit:       limit,
		})
		if err != nil {
			log.Printf("[ProductPerformance][grouped-filter-options] failed trace_id=%s mode=%s levels=%v fields=%d: %v", traceID, mode, groupLevels, len(fields), err)
			http.Error(w, "urun performans filtre secenekleri alinamadi: "+err.Error(), http.StatusInternalServerError)
			return
		}
		_ = json.NewEncoder(w).Encode(options)
	}
}

func splitCSVQuery(value string) []string {
	parts := strings.Split(value, ",")
	out := make([]string, 0, len(parts))
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part != "" {
			out = append(out, part)
		}
	}
	return out
}

func intQuery(r *http.Request, key string, fallback int) int {
	raw := strings.TrimSpace(r.URL.Query().Get(key))
	if raw == "" {
		return fallback
	}
	n, err := strconv.Atoi(raw)
	if err != nil || n <= 0 {
		return fallback
	}
	return n
}

func boolQuery(r *http.Request, key string, fallback bool) bool {
	raw := strings.TrimSpace(strings.ToLower(r.URL.Query().Get(key)))
	if raw == "" {
		return fallback
	}
	return raw == "1" || raw == "true" || raw == "yes" || raw == "on"
}
