package reports

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/TaruLab/keluargamart-backend/internal/auth"
	"github.com/TaruLab/keluargamart-backend/pkg/httpresponse"
	"github.com/TaruLab/keluargamart-backend/pkg/logger"
	"github.com/TaruLab/keluargamart-backend/pkg/middleware"
)

func parseFilter(r *http.Request) (page, perPage int, search, dateFrom, dateTo string) {
	q := r.URL.Query()
	page, _ = strconv.Atoi(q.Get("page"))
	if page <= 0 {
		page = 1
	}
	perPage, _ = strconv.Atoi(q.Get("per_page"))
	if perPage <= 0 {
		perPage = 15
	}
	if perPage > 100 {
		perPage = 100
	}
	search = strings.TrimSpace(q.Get("search"))
	dateFrom = strings.TrimSpace(q.Get("date_from"))
	dateTo = strings.TrimSpace(q.Get("date_to"))
	return
}

func (h *Handler) storeIDsFromContext(r *http.Request) []int64 {
	scope := auth.StoreScopeFrom(r.Context())
	if scope.PlatformWide() {
		return nil
	}
	return scope.IDs()
}

func (h *Handler) warehouseIDsFromContext(r *http.Request) []int64 {
	storeIDs := h.storeIDsFromContext(r)
	if len(storeIDs) == 0 {
		return nil
	}
	if repo, ok := h.svc.store.(*Repository); ok {
		whs, err := repo.q.WarehousesForStores(r.Context(), storeIDs)
		if err == nil && len(whs) > 0 {
			return whs
		}
	}
	return nil
}

// SalesByCustomer serves GET /reports/sales-by-customer
func (h *Handler) SalesByCustomer(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, dateFrom, dateTo := parseFilter(r)
	storeIDs := h.storeIDsFromContext(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []SalesByCustomerRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.SalesByCustomer(r.Context(), BreakdownFilter{
		Page:     page,
		PerPage:  perPage,
		Search:   search,
		DateFrom: dateFrom,
		DateTo:   dateTo,
		StoreIDs: storeIDs,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// SalesByProduct serves GET /reports/sales-by-product
func (h *Handler) SalesByProduct(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, dateFrom, dateTo := parseFilter(r)
	storeIDs := h.storeIDsFromContext(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []SalesByProductRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.SalesByProduct(r.Context(), BreakdownFilter{
		Page:     page,
		PerPage:  perPage,
		Search:   search,
		DateFrom: dateFrom,
		DateTo:   dateTo,
		StoreIDs: storeIDs,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// PurchasesBySupplier serves GET /reports/purchases-by-supplier
func (h *Handler) PurchasesBySupplier(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, dateFrom, dateTo := parseFilter(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []PurchasesBySupplierRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.PurchasesBySupplier(r.Context(), BreakdownFilter{
		Page:     page,
		PerPage:  perPage,
		Search:   search,
		DateFrom: dateFrom,
		DateTo:   dateTo,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// PurchasesByProduct serves GET /reports/purchases-by-product
func (h *Handler) PurchasesByProduct(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, dateFrom, dateTo := parseFilter(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []PurchasesByProductRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.PurchasesByProduct(r.Context(), BreakdownFilter{
		Page:     page,
		PerPage:  perPage,
		Search:   search,
		DateFrom: dateFrom,
		DateTo:   dateTo,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// ReceivablesAging serves GET /reports/receivables-aging
func (h *Handler) ReceivablesAging(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, _, _ := parseFilter(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []AgingRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.ReceivablesAging(r.Context(), AgingFilter{
		Page:    page,
		PerPage: perPage,
		Search:  search,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// PayablesAging serves GET /reports/payables-aging
func (h *Handler) PayablesAging(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, _, _ := parseFilter(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []AgingRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.PayablesAging(r.Context(), AgingFilter{
		Page:    page,
		PerPage: perPage,
		Search:  search,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// StockValuation serves GET /reports/stock-valuation
func (h *Handler) StockValuation(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, _, _ := parseFilter(r)
	whIDs := h.warehouseIDsFromContext(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []StockValuationRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.StockValuation(r.Context(), StockValuationFilter{
		Page:         page,
		PerPage:      perPage,
		Search:       search,
		WarehouseIDs: whIDs,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// StockMovements serves GET /reports/stock-movements
func (h *Handler) StockMovements(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	page, perPage, search, dateFrom, dateTo := parseFilter(r)
	whIDs := h.warehouseIDsFromContext(r)

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OKPaginated(w, http.StatusOK, reqID, []StockMovementRow{}, page, perPage, 0)
		return
	}

	list, total, err := detailed.StockMovements(r.Context(), StockMovementsFilter{
		Page:         page,
		PerPage:      perPage,
		Search:       search,
		DateFrom:     dateFrom,
		DateTo:       dateTo,
		WarehouseIDs: whIDs,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OKPaginated(w, http.StatusOK, reqID, list, page, perPage, total)
}

// StockCard serves GET /reports/stock-card
func (h *Handler) StockCard(w http.ResponseWriter, r *http.Request) {
	reqID := middleware.RequestIDFrom(r.Context())
	q := r.URL.Query()
	productID, _ := strconv.ParseInt(q.Get("product_id"), 10, 64)
	if productID <= 0 {
		httpresponse.OK(w, http.StatusOK, reqID, []StockCardRow{})
		return
	}
	warehouseID, _ := strconv.ParseInt(q.Get("warehouse_id"), 10, 64)
	dateFrom := strings.TrimSpace(q.Get("date_from"))
	dateTo := strings.TrimSpace(q.Get("date_to"))

	detailed, ok := h.svc.store.(DetailedReportsStore)
	if !ok {
		httpresponse.OK(w, http.StatusOK, reqID, []StockCardRow{})
		return
	}

	whIDs := h.warehouseIDsFromContext(r)
	rows, err := detailed.StockCard(r.Context(), StockCardFilter{
		ProductID:    productID,
		WarehouseID:  warehouseID,
		DateFrom:     dateFrom,
		DateTo:       dateTo,
		WarehouseIDs: whIDs,
	})
	if err != nil {
		httpresponse.Internal(w, reqID, logger.FromContext(r.Context()), err)
		return
	}
	httpresponse.OK(w, http.StatusOK, reqID, rows)
}
