package controllers

import (
	"nearle/db"
	"nearle/domain"
	"nearle/models"
	"nearle/utils"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"
)

const (
	base = `SELECT COUNT(*) AS total,
		SUM(CASE WHEN orderstatus = 'created' THEN 1 ELSE 0 END) AS created,
		SUM(CASE WHEN orderstatus = 'pending' THEN 1 ELSE 0 END) AS pending,
		SUM(CASE WHEN orderstatus = 'processing' THEN 1 ELSE 0 END) AS processing,
		SUM(CASE WHEN orderstatus = 'delivered' THEN 1 ELSE 0 END) AS delivered,
		SUM(CASE WHEN orderstatus = 'cancelled' THEN 1 ELSE 0 END) AS cancelled`
)

func CreateCustomerOrder(c *fiber.Ctx) error {

	var data models.Customerorder

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	tx := db.DB.Begin()

	data.Orders.Orderid = domain.GetSequenceno(data.Orders.Tenantid, "ORD")

	if data.Orders.Customerid != 0 && data.Orders.Deliveryid != 0 {

		// utils.Logger.Debug("coming to existing for creating order with location")

		pid, err := domain.UpdateCustomerv2(data.Pickup)
		if err != nil {

			return c.JSON(fiber.Map{
				"code":    http.StatusConflict,
				"message": err.Error(),
				"status":  false,
			})

		}
		utils.Logger.Infow("Pickup Location ID updated", "pid", pid)

		data.Orders.Pickuplocationid = pid

		did, err1 := domain.UpdateCustomerv2(data.Drop)
		if err1 != nil {

			return c.JSON(fiber.Map{
				"code":    http.StatusConflict,
				"message": err1.Error(),
				"status":  false,
			})

		}

		utils.Logger.Infow("Delivery Location ID updated", "did", did)
		data.Orders.Deliverylocationid = did

		t1 := tx.Create(&data.Orders)
		if t1.Error != nil {

			utils.Logger.Errorw("Tx Create Error", "error", t1.Error)

			tx.Rollback()
			return c.JSON(fiber.Map{
				"code":    http.StatusConflict,
				"message": t1.Error,
				"status":  false,
			})
		}

	} else {

		if data.Orders.Customerid == 0 {

			cid := domain.CheckCustomer(data.Pickup.Contactno)
			if cid != 0 {

				pid, err := domain.UpdateCustomerv2(data.Pickup)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err.Error(),
						"status":  false,
					})

				}

				utils.Logger.Infow("Customer exists, updating", "pid", pid)

				data.Orders.Pickuplocationid = pid

			} else {

				cid, err := domain.CreateCustomerv2(data.Pickup)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err,
						"status":  false,
					})

				}

				utils.Logger.Infow("Created new pickup customer", "customerid", cid.Customerid)

				data.Orders.Customerid = cid.Customerid
				data.Orders.Pickuplocationid = cid.Locationid

			}

		}

		if data.Orders.Deliveryid == 0 {

			utils.Logger.Infow("Creating new drop customer")

			cid := domain.CheckCustomer(data.Drop.Contactno)
			if cid != 0 {

				pid, err := domain.UpdateCustomerv2(data.Drop)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err.Error(),
						"status":  false,
					})

				}

				data.Orders.Deliverylocationid = pid

			} else {

				did, err := domain.CreateCustomerv2(data.Drop)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err,
						"status":  false,
					})

				}

				utils.Logger.Infow("Created new drop customer", "customerid", did.Customerid)

				data.Orders.Deliveryid = did.Customerid
				data.Orders.Deliverylocationid = did.Locationid

			}

		}

		t2 := tx.Create(&data.Orders)
		if t2.Error != nil {

			utils.Logger.Errorw("Tx Create Error", "error", t2.Error)
			tx.Rollback()
			return t2.Error
		}

	}

	domain.UpdateSeqno(data.Orders.Tenantid, "ORD")

	err := tx.Commit().Error

	result := domain.GetOrderbyid(data.Orders.Orderheaderid)

	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})

	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": result,
	})

}

func CreateCustomerOrderv2(c *fiber.Ctx) error {

	var data models.Customerorder

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	tx := db.DB.Begin()

	data.Orders.Orderid = domain.GetSequenceno(data.Orders.Tenantid, "ORD")

	if data.Orders.Customerid != 0 && data.Orders.Deliveryid != 0 {

		utils.Logger.Infow("Normal creating order")

		err := domain.UpdateCustomerv1(data.Pickup)
		if err != nil {

			return c.JSON(fiber.Map{
				"code":    http.StatusConflict,
				"message": err.Error(),
				"status":  false,
			})

		}

		err1 := domain.UpdateCustomerv1(data.Drop)
		if err1 != nil {

			return c.JSON(fiber.Map{
				"code":    http.StatusConflict,
				"message": err1.Error(),
				"status":  false,
			})

		}

		t1 := tx.Create(&data.Orders)
		if t1.Error != nil {

			utils.Logger.Errorw("Tx Create Error", "error", t1.Error)

			tx.Rollback()
			return c.JSON(fiber.Map{
				"code":    http.StatusConflict,
				"message": t1.Error,
				"status":  false,
			})
		}

	} else {

		utils.Logger.Infow("Creating customer and order")

		if data.Orders.Customerid == 0 {

			cid := domain.CheckCustomer(data.Pickup.Contactno)
			if cid != 0 {

				data.Pickup.Customerid = cid

				err := domain.UpdateCustomerv1(data.Pickup)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err.Error(),
						"status":  false,
					})

				}

				data.Orders.Customerid = cid

			} else {

				cid, err := domain.CreateCustomerv1(data.Pickup)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err,
						"status":  false,
					})

				}

				data.Orders.Customerid = cid

			}

		}

		if data.Orders.Deliveryid == 0 {

			dcid := domain.CheckCustomer(data.Drop.Contactno)

			if dcid != 0 {

				data.Drop.Customerid = dcid

				err := domain.UpdateCustomerv1(data.Drop)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err.Error(),
						"status":  false,
					})

				}

				data.Orders.Deliveryid = dcid

			} else {

				did, err := domain.CreateCustomerv1(data.Drop)
				if err != nil {

					return c.JSON(fiber.Map{
						"code":    http.StatusConflict,
						"message": err,
						"status":  false,
					})
				}

				data.Orders.Deliveryid = did

			}

		}

		t2 := tx.Create(&data.Orders)
		if t2.Error != nil {

			utils.Logger.Errorw("Tx Create Error", "error", t2.Error)
			tx.Rollback()
			return t2.Error
		}

	}

	domain.UpdateSeqno(data.Orders.Tenantid, "ORD")

	err := tx.Commit().Error

	utils.Logger.Infow("Order created with header ID", "orderheaderid", data.Orders.Orderheaderid)

	result := domain.GetOrderbyidV2(data.Orders.Orderheaderid)

	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})

	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": result,
	})

}

func CreateOrder(c *fiber.Ctx) error {
	// Wrapper to parse "orders" key
	type OrderWrapper struct {
		Orders models.Orders `json:"orders"`
	}

	var wrapper OrderWrapper

	// ✅ Parse the JSON body
	if err := c.BodyParser(&wrapper); err != nil {
		utils.Logger.Errorw("BodyParser error", "error", err)
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	data := wrapper.Orders
	utils.Logger.Infow("Creating Order", "tenantid", data.Tenantid)

	// ❌ Check for missing tenantid
	if data.Tenantid == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Tenant ID is required",
			"status":  false,
		})
	}

	// ✅ Fallback if orderdate is missing
	if strings.TrimSpace(data.Orderdate) == "" {
		data.Orderdate = time.Now().Format("2006-01-02 15:04:05")
	}

	// ✅ Start DB transaction
	tx := db.DB.Begin()

	// ✅ Generate order ID
	data.Orderid = domain.GetSequenceno(data.Tenantid, "ORD")

	// ✅ Insert order
	if err := tx.Create(&data).Error; err != nil {
		tx.Rollback()
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Failed to create order",
			"status":  false,
		})
	}

	// ✅ Update order sequence
	domain.UpdateSeqno(data.Tenantid, "ORD")

	// ✅ Commit transaction
	if err := tx.Commit().Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Transaction failed",
			"status":  false,
		})
	}

	// ✅ Fetch inserted order by ID
	result := domain.GetOrderbyid(data.Orderheaderid)

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": result,
	})
}

func CreateOrders(c *fiber.Ctx) error {

	var orders []models.Orders

	if err := c.BodyParser(&orders); err != nil {
		return err
	}

	tx := db.DB.Begin()

	for i := range orders {

		// utils.Logger.Debugf("tenantid: %v", orders[i].Tenantid)

		orders[i].Orderid = domain.GetSequenceno(orders[i].Tenantid, "ORD")
		t1 := tx.Create(&orders[i])
		if t1.Error != nil {
			utils.Logger.Errorw("Tx Create Error", "error", t1.Error)
			tx.Rollback()
			return c.JSON(fiber.Map{
				"code":    http.StatusInternalServerError,
				"message": "Error creating order",
				"status":  false,
			})
		}
		domain.UpdateSeqno(orders[i].Tenantid, "ORD")
	}

	tx.Commit()

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
	})

}

func UpdateOrder(c *fiber.Ctx) error {

	var orders models.Orders

	if err := c.BodyParser(&orders); err != nil {
		return err
	}

	tx := db.DB.Begin()

	t1 := tx.Where("orderheaderid=?", orders.Orderheaderid).Updates(&orders)
	if t1.Error != nil {
		utils.Error("UpdateOrder t1 updates error", "error", t1.Error)
		tx.Rollback()
		return c.JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Error updating order",
			"status":  false,
		})
	}

	tx.Commit()

	return c.JSON(fiber.Map{
		"code":    http.StatusAccepted,
		"message": "Success",
		"status":  true,
	})

}

func UpdateMultipleOrders(c *fiber.Ctx) error {

	var orders []models.Orders

	// Parse JSON array input
	if err := c.BodyParser(&orders); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	tx := db.DB.Begin()

	for _, order := range orders {

		// Update each order by orderheaderid
		if err := tx.Model(&models.Orders{}).
			Where("orderheaderid = ?", order.Orderheaderid).
			Updates(map[string]interface{}{
				"orderstatus": order.Orderstatus,
				"cancelled":   order.Cancelled,
			}).Error; err != nil {

			tx.Rollback()
			return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
				"code":    http.StatusInternalServerError,
				"message": "Failed to update order " + strconv.Itoa(order.Orderheaderid),
				"status":  false,
			})
		}
	}

	if err := tx.Commit().Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Transaction commit failed",
			"status":  false,
		})
	}

	return c.Status(http.StatusAccepted).JSON(fiber.Map{
		"code":    http.StatusAccepted,
		"message": "Orders updated successfully",
		"status":  true,
	})
}

func GetOrdersv2(c *fiber.Ctx) error {

	var result []models.OrderInfo

	tid, _ := strconv.Atoi(c.Query("tenantid"))
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	cid, _ := strconv.Atoi(c.Query("customerid"))
	mid, _ := strconv.Atoi(c.Query("customerid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	uid, _ := strconv.Atoi(c.Query("appuserid"))
	Pageno, _ := strconv.Atoi(c.Query("pageno"))
	Pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	stat := c.Query("status")
	fdate := c.Query("fromdate")
	tdate := c.Query("todate")

	if tid != 0 {

		result = domain.GetTenantOrdersv2(stat, fdate, tdate, tid, Pageno, Pagesize)

	} else if pid != 0 {

		result = domain.GetPartnerOrdersv2(stat, fdate, tdate, pid, Pageno, Pagesize)

	} else if cid != 0 {

		result = domain.GetCustomerOrdersv2(stat, fdate, tdate, cid, mid, Pageno, Pagesize)

	} else if aid != 0 {

		result = domain.GetAdminOrdersv2(stat, fdate, tdate, aid, Pageno, Pagesize)

	} else if uid != 0 {

		result = domain.GetUserOrdersv2(stat, fdate, tdate, uid, Pageno, Pagesize)

	} else {

		result = domain.GetAllOrdersv2(stat, fdate, tdate, Pageno, Pagesize)

	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": result,
	})

}

func GetOrders(c *fiber.Ctx) error {
	var result []models.OrderInfo
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	tid, _ := strconv.Atoi(c.Query("tenantid"))
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	cid, _ := strconv.Atoi(c.Query("customerid"))
	mid, _ := strconv.Atoi(c.Query("moduleid"))
	lid, _ := strconv.Atoi(c.Query("locationid"))
	uid, _ := strconv.Atoi(c.Query("appuserid"))
	configid, _ := strconv.Atoi(c.Query("configid"))

	stat := c.Query("status")
	fdate := c.Query("fromdate")
	tdate := c.Query("todate")
	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	keyword := c.Query("keyword")

	if pageno <= 0 {
		pageno = 1
	}
	if pagesize <= 0 {
		pagesize = 10
	}

	var info models.DeliveryQuery
	info.Partnerid = pid
	info.Tenantid = tid
	info.UserID = uid
	info.Appuserid = uid
	info.Locationid = lid
	info.Configid = configid
	info.Fromdate = fdate
	info.ToDate = tdate
	info.Status = stat
	info.Pageno = pageno
	info.Pagesize = pagesize
	info.Keyword = keyword
	info.Applocationid = aid

	if tid != 0 && lid != 0 && aid != 0 {
		result = domain.GetTenantLocationAppOrders(info)
	} else if tid != 0 && lid != 0 {
		result = domain.GetTenantLocationOrders(info)
	} else if tid != 0 && aid != 0 {
		result = domain.GetTenantAppOrders(info)
	} else if tid != 0 {
		result = domain.GetTenantOrders(info)
	} else if aid != 0 {
		result = domain.GetAppOrders(info)
	} else if pid != 0 {
		result = domain.GetPartnerOrders(stat, fdate, tdate, pid, pageno, pagesize, keyword)
	} else if cid != 0 {
		result = domain.GetCustomerOrders(stat, fdate, tdate, cid, mid, pageno, pagesize, keyword)
	} else if lid != 0 {
		result = domain.GetLocationOrders(stat, fdate, tdate, lid, pageno, pagesize, keyword)
	} else if uid != 0 {
		result = domain.GetUserOrders(stat, fdate, tdate, uid, pageno, pagesize, keyword)
	} else {
		result = domain.GetAllOrders(stat, fdate, tdate, aid, pageno, pagesize, keyword)
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": result,
	})
}

func GetOrdersbytenant(c *fiber.Ctx) error {

	tid, _ := strconv.Atoi(c.Query("tenantid"))
	stat := c.Query("status")
	fdate := c.Query("fromdate")
	tdate := c.Query("todate")

	var q1 string
	var data []models.OrderInfo

	var params []interface{}
	params = append(params, tid)

	if stat != "" {

		q1 = `SELECT a.orderheaderid,a.tenantid,a.partnerid,a.locationid,a.orderid,a.orderdate,a.orderstatus,a.pending,
			a.customerid,b.firstname AS customername,b.contactno,a.pickupaddress,a.pickuplat,a.pickuplong,
			a.ordernotes,a.deliverylocationid,a.deliveryaddress, a.deliverylat ,a.deliverylong
			FROM orders a
			INNER JOIN customers b ON a.customerid=b.customerid
			where a.tenantid=? and a.orderstatus='created' and orderdate between ? and ? order by a.orderheaderid desc`
		params = append(params, fdate, tdate)

	} else {

		q1 = `SELECT a.orderheaderid,a.tenantid,a.partnerid,a.locationid,a.orderid,a.orderdate,a.orderstatus,a.pending,
			a.customerid,b.firstname AS customername,b.contactno,a.pickupaddress,a.pickuplat,a.pickuplong,
			a.ordernotes,a.deliverylocationid,a.deliveryaddress, a.deliverylat ,a.deliverylong
			FROM orders a
			INNER JOIN customers b ON a.customerid=b.customerid
			where a.tenantid=? and a.orderstatus='cancelled' and orderdate between ? and ? order by a.orderheaderid desc`
		params = append(params, fdate, tdate)

	}

	db.DB.Raw(q1, params...).Find(&data)

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": data,
	})

}

func GetTenantLocationSummary(c *fiber.Ctx) error {

	tid, _ := strconv.Atoi(c.Query("tenantid"))
	lid, _ := strconv.Atoi(c.Query("locationid"))

	var data []models.TenantLocationSummary
	var q1 string

	if lid == 0 {

		q1 = `SELECT 
			a.locationid,b.locationname,b.suburb as locationsuburb,	
			COUNT(*) AS total,
			COUNT(CASE WHEN a.orderstatus = 'created' THEN 1 ELSE NULL END) AS created,
			COUNT(CASE WHEN a.orderstatus = 'pending' THEN 1 ELSE NULL END) AS pending,
			COUNT(CASE WHEN a.orderstatus = 'delivered' THEN 1 ELSE NULL END) AS delivered,
			COUNT(CASE WHEN a.orderstatus = 'cancelled' THEN 1 ELSE NULL END) AS cancelled
			FROM orders a inner JOIN tenantlocations b ON a.locationid=b.locationid
			WHERE a.tenantid= ? GROUP BY a.locationid`
		db.DB.Raw(q1, tid).Find(&data)

	} else {

		q1 = `SELECT 
			a.locationid,b.locationname,	
			COUNT(*) AS total,
			COUNT(CASE WHEN a.orderstatus = 'created' THEN 1 ELSE NULL END) AS created,
			COUNT(CASE WHEN a.orderstatus = 'pending' THEN 1 ELSE NULL END) AS pending,
			COUNT(CASE WHEN a.orderstatus = 'delivered' THEN 1 ELSE NULL END) AS delivered,
			COUNT(CASE WHEN a.orderstatus = 'cancelled' THEN 1 ELSE NULL END) AS cancelled
			FROM orders a inner JOIN tenantlocations b ON a.locationid=b.locationid
			WHERE a.tenantid= ? and a.locationid= ? GROUP BY a.locationid`
		db.DB.Raw(q1, tid, lid).Find(&data)

	}

	// utils.Logger.Debugf("Query: %s", q1)

	db.DB.Raw(q1, tid).Find(&data)

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}

func GetlocationOrderSummary(c *fiber.Ctx) error {
	tenantIDStr := c.Query("tenantid")
	tenantID, _ := strconv.Atoi(tenantIDStr)

	var data []models.Ordersummary
	var q1 string
	var params []interface{}

	q1 = `
		SELECT b.locationname,a.applocationid, COUNT(*) AS total,
			SUM(CASE WHEN orderstatus = 'created' THEN 1 ELSE 0 END) AS created,
			SUM(CASE WHEN orderstatus = 'pending' THEN 1 ELSE 0 END) AS pending,
			SUM(CASE WHEN orderstatus = 'processing' THEN 1 ELSE 0 END) AS processing,
			SUM(CASE WHEN orderstatus = 'delivered' THEN 1 ELSE 0 END) AS delivered,
			SUM(CASE WHEN orderstatus = 'cancelled' THEN 1 ELSE 0 END) AS cancelled
		FROM orders a 
		INNER JOIN app_location b ON a.applocationid=b.applocationid`

	if tenantID != 0 {
		q1 += " WHERE a.tenantid = ?"
		params = append(params, tenantID)
	}

	q1 += " GROUP BY a.applocationid, b.locationname"

	if err := db.DB.Raw(q1, params...).Scan(&data).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}

func GetOrderInsight(c *fiber.Ctx) error {

	tenantIDStr := c.Query("tenantid")
	tenantID, _ := strconv.Atoi(tenantIDStr)

	var locations []models.OrderInsight
	var params []interface{}

	// Query 1: Get distinct locations
	q1 := `
		SELECT DISTINCT 
			a.applocationid, 
			b.locationname
		FROM orders a
		INNER JOIN app_location b 
			ON a.applocationid = b.applocationid
		WHERE b.status = 'Active'
	`

	if tenantID != 0 {
		q1 += " AND a.tenantid = ?"
		params = append(params, tenantID)
	}

	// ✅ OLD STYLE DB USAGE
	if err := db.DB.Raw(q1, params...).Scan(&locations).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	// Query 2: Monthly order counts
	q2 := `
		SELECT 
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 1 THEN 1 ELSE 0 END), 0) AS jan,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 2 THEN 1 ELSE 0 END), 0) AS feb,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 3 THEN 1 ELSE 0 END), 0) AS mar,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 4 THEN 1 ELSE 0 END), 0) AS apr,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 5 THEN 1 ELSE 0 END), 0) AS may,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 6 THEN 1 ELSE 0 END), 0) AS jun,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 7 THEN 1 ELSE 0 END), 0) AS jul,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 8 THEN 1 ELSE 0 END), 0) AS aug,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 9 THEN 1 ELSE 0 END), 0) AS sep,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 10 THEN 1 ELSE 0 END), 0) AS oct,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 11 THEN 1 ELSE 0 END), 0) AS nov,
			COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 12 THEN 1 ELSE 0 END), 0) AS dece
		FROM orders a
		WHERE a.applocationid = ?
		  AND EXTRACT(YEAR FROM a.orderdate) = EXTRACT(YEAR FROM CURRENT_DATE)
	`

	if tenantID != 0 {
		q2 += " AND a.tenantid = ?"
	}

	// Fetch monthly data per location
	for i := range locations {
		var orderMonths models.Ordermonths

		if tenantID != 0 {
			if err := db.DB.Raw(
				q2,
				locations[i].Applocationid,
				tenantID,
			).Scan(&orderMonths).Error; err != nil {
				return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
					"code":    http.StatusInternalServerError,
					"message": err.Error(),
					"status":  false,
				})
			}
		} else {
			if err := db.DB.Raw(
				q2,
				locations[i].Applocationid,
			).Scan(&orderMonths).Error; err != nil {
				return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
					"code":    http.StatusInternalServerError,
					"message": err.Error(),
					"status":  false,
				})
			}
		}

		locations[i].Ordermonths = &orderMonths
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": locations,
	})
}

// func GetOrderInsight(c *fiber.Ctx) error {

// 	var data []models.OrderInsight

// 	q1 := `SELECT distinct a.applocationid,b.locationname from orders a INNER JOIN app_location b ON a.applocationid=b.applocationid
// 	WHERE b.status='Active'`

// 	q2 := `SELECT a.applocationid,b.locationname,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 1 THEN 1 ELSE 0 END) AS jan,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 2 THEN 1 ELSE 0 END) AS feb,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 3 THEN 1 ELSE 0 END) AS mar,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 4 THEN 1 ELSE 0 END) AS apr,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 5 THEN 1 ELSE 0 END) AS may,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 6 THEN 1 ELSE 0 END) AS jun,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 7 THEN 1 ELSE 0 END) AS jul,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 8 THEN 1 ELSE 0 END) AS aug,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 9 THEN 1 ELSE 0 END) AS sep,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 10 THEN 1 ELSE 0 END) AS oct,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 11 THEN 1 ELSE 0 END) AS nov,
// 	SUM(CASE WHEN MONTH(a.orderdate) = 12 THEN 1 ELSE 0 END) AS dece
// 	FROM orders a
// 	INNER JOIN app_location b ON a.applocationid=b.applocationid
// 	where b.status='Active' and a.applocationid=? and year(a.orderdate)=year(curdate())
// 	GROUP BY b.locationname, a.applocationid
// 	ORDER BY month(a.orderdate) asc`

// 	err := db.DB.Raw(q1).Preload("Ordermonths", func(db *gorm.DB) *gorm.DB {
// 		return db.Raw(q2)
// 	}).Find(&data).Error

// 	//err := db.DB.Raw(q1).Find(&data).Error

// 	if err != nil {

// 		return c.JSON(fiber.Map{
// 			"code":    http.StatusConflict,
// 			"message": err.Error(),
// 			"status":  false,
// 		})

// 	}

// 	return c.JSON(fiber.Map{
// 			"code":    http.StatusOK,
// 			"message": "Success",
// 			"status":  true,
// 			"details": data,
// 		})

// }

func GetOrderSummary(c *fiber.Ctx) error {
	tid, _ := strconv.Atoi(c.Query("tenantid"))
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	cid, _ := strconv.Atoi(c.Query("customerid"))
	lid, _ := strconv.Atoi(c.Query("locationid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	fdate := c.Query("fromdate")
	tdate := c.Query("todate")

	var data models.Ordersummary
	var q1 string

	var params []interface{}
	q1 = base + ` 
FROM orders a
INNER JOIN tenants b 
  ON a.tenantid = b.tenantid
WHERE a.categoryid <> 2 
AND b.moduleid = 6`
	if tid != 0 {
		q1 += " AND a.tenantid=?"
		params = append(params, tid)
	}
	if lid != 0 && (tid != 0 || pid == 0) {
		q1 += " AND a.locationid=?"
		params = append(params, lid)
	}
	if pid != 0 {
		q1 += " AND a.partnerid=?"
		params = append(params, pid)
	}
	if cid != 0 {
		q1 += " AND a.customerid=?"
		params = append(params, cid)
	}
	if aid != 0 {
		q1 += " AND a.applocationid=?"
		params = append(params, aid)
	}
	if fdate != "" && tdate != "" {
		q1 += " AND a.deliverytime >= ? AND a.deliverytime < (?::date + INTERVAL '1 day')"
		params = append(params, fdate, tdate)
	}

	utils.Logger.Debugw("CancelOrder-Query", "q1", q1)

	if err := db.DB.Raw(q1, params...).Scan(&data).Error; err != nil {
		return c.JSON(fiber.Map{
			"code":    500,
			"status":  false,
			"message": err.Error(),
		})
	}

	return c.JSON(fiber.Map{
		"code":    200,
		"status":  true,
		"message": "Success",
		"details": data,
	})
}

func GetCustomerOrderCount(cid int) int {

	var count int
	q1 := "SELECT count(*) as count FROM orders WHERE customerid=?"

	db.DB.Raw(q1, cid).Find(&count)
	return count

}

func UpdateOrderStatus(input models.Orders) error {

	tx := db.DB.Begin()

	t1 := tx.Where("orderheaderid=?", input.Orderheaderid).Updates(&input)
	if t1.Error != nil {
		utils.Error("UpdateOrderStatus t1 updates error", "error", t1.Error)
		tx.Rollback()
		return tx.Error
	}

	tx.Commit()
	return nil

}

// func CreateOrderv3(c *fiber.Ctx) error {
// 	type OrderWrapper struct {
// 		Orders models.Orders `json:"orders"`
// 	}

// 	var wrapper OrderWrapper

// 	// Parse JSON body
// 	if err := c.BodyParser(&wrapper); err != nil {
// 		utils.Logger.Errorw("BodyParser error", "error", err)
// 		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
// 			"code":    http.StatusBadRequest,
// 			"message": "Invalid request body",
// 			"status":  false,
// 		})
// 	}

// 	data := wrapper.Orders

// 	// Check required field
// 	if data.Tenantid == 0 {
// 		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
// 			"code":    http.StatusBadRequest,
// 			"message": "Tenant ID is required",
// 			"status":  false,
// 		})
// 	}

// 	// Default values if missing
// 	if strings.TrimSpace(data.Orderdate) == "" {
// 		data.Orderdate = time.Now().Format("2006-01-02 15:04:05")
// 	}

// 	if strings.TrimSpace(data.Deliverytime) == "" {
// 		data.Deliverytime = time.Now().Format("2006-01-02 15:04:05")
// 	}

// 	// Start transaction
// 	tx := db.DB.Begin()

// 	// Generate Order ID
// 	data.Orderid = domain.GetSequenceno(data.Tenantid, "ORD")

// 	// Insert order
// 	if err := tx.Create(&data).Error; err != nil {
// 		tx.Rollback()
// 		log.Println("Create order error:", err)
// 		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
// 			"code":    http.StatusInternalServerError,
// 			"message": "Failed to create order",
// 			"status":  false,
// 		})
// 	}

// 	// Insert order items
// 	for _, item := range data.Items {
// 		item.Orderheaderid = data.Orderheaderid
// 		item.Tenantid = data.Tenantid
// 		item.Locationid = data.Locationid

// 		if err := tx.Table("orderdetails").Create(&item).Error; err != nil {
// 			tx.Rollback()
// 			log.Println("Insert item error:", err)
// 			return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
// 				"code":    http.StatusInternalServerError,
// 				"message": "Failed to insert order item",
// 				"status":  false,
// 			})
// 		}
// 	}

// 	// Update sequence
// 	if err := domain.UpdateSeqno(data.Tenantid, "ORD"); err != nil {
// 		log.Println("Sequence update error:", err)
// 	}

// 	// Commit
// 	if err := tx.Commit().Error; err != nil {
// 		log.Println("Commit failed:", err)
// 		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
// 			"code":    http.StatusInternalServerError,
// 			"message": "Transaction failed",
// 			"status":  false,
// 		})
// 	}

// 	// Return order data
// 	var order models.Orders
// 	if err := db.DB.Where("orderheaderid = ?", data.Orderheaderid).First(&order).Error; err != nil {
// 		log.Println("Fetch order error:", err)
// 		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
// 			"code":    http.StatusInternalServerError,
// 			"message": "Failed to fetch order details",
// 			"status":  false,
// 		})
// 	}

// 	// 🔽 Manually fetch order items and assign to Items
// 	var items []models.OrderDetail
// 	if err := db.DB.Table("orderdetails").Where("orderheaderid = ?", data.Orderheaderid).Find(&items).Error; err != nil {
// 		log.Println("Fetch order items error:", err)
// 	}
// 	order.Items = items

// 	return c.Status(http.StatusOK).JSON(fiber.Map{
// 		"code":    http.StatusOK,
// 		"message": "Order created successfully",
// 		"status":  true,
// 		"details": order,
// 	})

// }

func CreateOrderv3(c *fiber.Ctx) error {
	type OrderWrapper struct {
		Orders models.Orders `json:"orders"`
	}

	var wrapper OrderWrapper

	if err := c.BodyParser(&wrapper); err != nil {
		utils.Logger.Errorw("BodyParser error", "error", err)
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	data := wrapper.Orders

	if data.Tenantid == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Tenant ID is required",
			"status":  false,
		})
	}

	if strings.TrimSpace(data.Orderdate) == "" {
		data.Orderdate = time.Now().Format("2006-01-02 15:04:05")
	}

	if strings.TrimSpace(data.Deliverytime) == "" {
		data.Deliverytime = time.Now().Format("2006-01-02 15:04:05")
	}

	tx := db.DB.Begin()

	data.Orderid = domain.GetSequenceno(data.Tenantid, "ORD")

	if err := tx.Create(&data).Error; err != nil {
		tx.Rollback()
		utils.Logger.Errorw("Create order error", "error", err)
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Failed to create order",
			"status":  false,
		})
	}

	for _, item := range data.Items {
		item.Orderheaderid = data.Orderheaderid
		item.Tenantid = data.Tenantid
		item.Locationid = data.Locationid

		if err := tx.Table("orderdetails").Create(&item).Error; err != nil {
			tx.Rollback()
			utils.Logger.Errorw("Insert item error", "error", err)
			return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
				"code":    http.StatusInternalServerError,
				"message": "Failed to insert order item",
				"status":  false,
			})
		}

		stock := models.Productstock{
			Tenantid:   data.Tenantid,
			Stockdate:  time.Now(),
			Locationid: data.Locationid,
			Productid:  item.Productid,
			Quantity:   int(item.Orderqty),
			Stocktype:  "out",
			Status:     "Active",
		}

		if err := tx.Table("productstocks").Create(&stock).Error; err != nil {
			tx.Rollback()
			utils.Logger.Errorw("Insert product stock error", "error", err)
			return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
				"code":    http.StatusInternalServerError,
				"message": "Failed to insert product stock",
				"status":  false,
			})
		}
	}

	if err := domain.UpdateSeqno(data.Tenantid, "ORD"); err != nil {
		utils.Logger.Errorw("Sequence update error", "error", err)
	}

	if err := tx.Commit().Error; err != nil {
		utils.Logger.Errorw("Commit failed", "error", err)
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Transaction failed",
			"status":  false,
		})
	}

	var order models.Orders
	if err := db.DB.Where("orderheaderid = ?", data.Orderheaderid).First(&order).Error; err != nil {
		utils.Logger.Errorw("Fetch order error", "error", err)
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Failed to fetch order details",
			"status":  false,
		})
	}

	var items []models.OrderDetail
	if err := db.DB.Table("orderdetails").Where("orderheaderid = ?", data.Orderheaderid).Find(&items).Error; err != nil {
		utils.Logger.Errorw("Fetch order items error", "error", err)
	}
	order.Items = items

	return c.Status(http.StatusOK).JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Order created successfully",
		"status":  true,
		"details": order,
	})
}

func GetOrderDetails(c *fiber.Ctx) error {
	orderHeaderIDStr := c.Query("orderheaderid")
	if orderHeaderIDStr == "" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    400,
			"message": "orderheaderid is required",
			"status":  false,
			"details": []interface{}{},
		})
	}

	orderHeaderID, err := strconv.Atoi(orderHeaderIDStr)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    400,
			"message": "invalid orderheaderid",
			"status":  false,
			"details": []interface{}{},
		})
	}

	details, orderAmount, totalTaxAmount, err := domain.GetOrderDetailsByHeaderID(orderHeaderID)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"code":    500,
			"message": "Failed to fetch order details",
			"status":  false,
			"details": []interface{}{},
		})
	}

	return c.JSON(fiber.Map{
		"code": 200,
		"pricedetails": fiber.Map{
			"orderamount":    orderAmount,
			"totaltaxamount": totalTaxAmount,
		},
		"details": details,
		"message": "Success",
		"status":  true,
	})
}

func GetCustomerOrders(c *fiber.Ctx) error {
	customerID := c.Query("customerid")
	tenantID := c.Query("tenantid")
	moduleID := c.Query("moduleid")
	fromDate := c.Query("fromdate")
	toDate := c.Query("todate")
	orderStatus := c.Query("orderstatus")
	keyword := c.Query("keyword")
	pageNo, _ := strconv.Atoi(c.Query("pageno", "1"))
	pageSize, _ := strconv.Atoi(c.Query("pagesize", "10"))

	if pageNo < 1 {
		pageNo = 1
	}
	if pageSize < 1 {
		pageSize = 10
	}
	offset := (pageNo - 1) * pageSize

	// Ensure response is [] not null
	orders := make([]models.CustomerOrder, 0)
	var orderdetails models.OrderDetails

	baseQuery := `
	SELECT DISTINCT a.orderheaderid, a.applocationid, a.tenantid, a.locationid, a.partnerid, a.configid, a.categoryid, a.subcategoryid, a.moduleid,
		a.orderid, a.orderstatus, a.orderdate, a.ordernotes, a.itemcount, a.deliverytime AS deliverytime,
		a.pending, a.processing, a.ready, a.delivered AS delivered, a.cancelled,
		a.deliverycharge, a.kms, a.customerid, a.pickupaddress, a.pickuplat, a.pickuplong,
		a.pickupcustomer, a.pickupcontactno, a.pickuplocation as pickupsuburb, a.pickupcity,
		a.deliveryid AS deliverycustomerid, a.deliveryaddress, a.deliverylat, a.deliverylong, a.deliverytype,
		a.deliverycustomer, a.deliverycontactno, a.deliverylocation as deliverysuburb, a.deliverycity, a.paymenttype, a.smsdelivery, a.taxamount,
		b.tenantname, b.tenanttoken, b.primarycontact AS tenantcontactno, b.postcode AS tenantpostcode, b.suburb AS tenantsuburb, b.city AS tenantcity,
		c.locationname, c.contactno AS locationcontactno, c.postcode AS locationpostcode, c.suburb AS locationsuburb, c.city AS locationcity,
		d.locationname AS applocation, f.orderstatus AS deliverystatus,
		f.deliveryid, f.assigntime, f.starttime, f.arrivaltime, f.pickuptime, f.deliverytime AS finaldeliverytime, f.canceltime,
		f.droplat, f.droplon, g.firstname AS rider
	FROM orders a
	INNER JOIN tenants b ON a.tenantid = b.tenantid
	INNER JOIN tenantlocations c ON a.locationid = c.locationid
	INNER JOIN app_location d ON a.applocationid = d.applocationid
	INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid
	LEFT JOIN deliveries f ON a.orderheaderid = f.orderheaderid
	LEFT JOIN app_users g ON f.userid = g.userid
	LEFT JOIN orderdetails h ON h.orderheaderid = a.orderheaderid
	WHERE 1=1
	`

	params := []interface{}{}

	if customerID != "" {
		baseQuery += " AND a.customerid = ?"
		params = append(params, customerID)
	}
	if tenantID != "" && tenantID != "0" {
		baseQuery += " AND a.tenantid = ?"
		params = append(params, tenantID)
	}
	if moduleID != "" {
		baseQuery += " AND a.moduleid = ?"
		params = append(params, moduleID)
	}
	if fromDate != "" && toDate != "" {
		baseQuery += " AND a.orderdate::date BETWEEN ?::date AND ?::date"
		params = append(params, fromDate, toDate)
	}
	if orderStatus != "" {
		baseQuery += " AND a.orderstatus = ?"
		params = append(params, orderStatus)
	}
	if keyword != "" {
		baseQuery += " AND h.productname LIKE ?"
		params = append(params, "%"+keyword+"%")
	}

	// ✅ Pagination enabled
	baseQuery += " ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?"
	params = append(params, pageSize, offset)

	utils.Logger.Debugw("Executing query", "query", baseQuery, "params", params)

	if err := db.DB.Raw(baseQuery, params...).Scan(&orders).Error; err != nil {
		utils.Logger.Errorw("Query execution error", "error", err)
		return c.Status(500).JSON(fiber.Map{
			"code":    500,
			"status":  false,
			"message": "Failed to fetch customer orders",
			"error":   err.Error(),
		})
	}

	for i := range orders {
		orderDetails, orderAmount, totalTaxAmount, _ := domain.GetOrderDetailsByHeaderID(orders[i].Orderheaderid)
		orders[i].OrderDetails = orderDetails
		orders[i].Orderamount = orderAmount
		orderdetails.Totaltaxamount = totalTaxAmount
	}

	return c.JSON(fiber.Map{
		"code":    200,
		"status":  true,
		"message": "Customer orders fetched successfully",
		"data":    orders,
	})
}

func GetOrderInsightDaily(c *fiber.Ctx) error {
	dbConn, ok := c.Locals("DB").(*gorm.DB)
	if !ok || dbConn == nil {
		return c.JSON(fiber.Map{
			"code":    500,
			"message": "Database connection not found",
			"status":  false,
		})
	}

	tenantIDStr := c.Query("tenantid")
	tenantID, _ := strconv.Atoi(tenantIDStr)

	var locations []models.OrderInsightv1
	var params []interface{}

	// ✅ Query 1: Get ALL locations (even without orders)
	q1 := `SELECT b.locationid, b.locationname
		   FROM tenantlocations b
		   WHERE b.status = 'Active'`

	if tenantID != 0 {
		q1 += " AND b.tenantid = ?"
		params = append(params, tenantID)
	}

	if err := dbConn.Raw(q1, params...).Scan(&locations).Error; err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

	// ✅ Query 2: Fetch order insights for each location
	q2 := `SELECT 
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 1 THEN 1 ELSE 0 END), 0) AS jan,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 2 THEN 1 ELSE 0 END), 0) AS feb,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 3 THEN 1 ELSE 0 END), 0) AS mar,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 4 THEN 1 ELSE 0 END), 0) AS apr,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 5 THEN 1 ELSE 0 END), 0) AS may,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 6 THEN 1 ELSE 0 END), 0) AS jun,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 7 THEN 1 ELSE 0 END), 0) AS jul,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 8 THEN 1 ELSE 0 END), 0) AS aug,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 9 THEN 1 ELSE 0 END), 0) AS sep,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 10 THEN 1 ELSE 0 END), 0) AS oct,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 11 THEN 1 ELSE 0 END), 0) AS nov,
		COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 12 THEN 1 ELSE 0 END), 0) AS dece
		FROM orders a
		WHERE a.locationid = ? AND EXTRACT(YEAR FROM a.orderdate) = EXTRACT(YEAR FROM CURRENT_DATE)`

	if tenantID != 0 {
		q2 += " AND a.tenantid = ?"
	}

	// ✅ Attach monthly order counts for each location
	for i := range locations {
		var orderMonths models.Ordermonths

		if tenantID != 0 {
			if err := dbConn.Raw(q2, locations[i].Locationid, tenantID).Scan(&orderMonths).Error; err != nil {
				return c.JSON(fiber.Map{
					"code":    http.StatusConflict,
					"message": err.Error(),
					"status":  false,
				})
			}
		} else {
			if err := dbConn.Raw(q2, locations[i].Locationid).Scan(&orderMonths).Error; err != nil {
				return c.JSON(fiber.Map{
					"code":    http.StatusConflict,
					"message": err.Error(),
					"status":  false,
				})
			}
		}

		locations[i].Ordermonths = &orderMonths
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": locations,
	})
}

func GetOrderSummaryDaily(c *fiber.Ctx) error {
	tid, _ := strconv.Atoi(c.Query("tenantid"))
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	cid, _ := strconv.Atoi(c.Query("customerid"))
	lid, _ := strconv.Atoi(c.Query("locationid"))
	fdate := c.Query("fromdate")
	tdate := c.Query("todate")

	var data []models.Ordersummarydaily
	var q1 string

	// 👇 join with tenants instead of locations
	baseWithTenant := base + `, t.tenantid, t.tenantname
		FROM orders o
		INNER JOIN tenants t ON o.tenantid = t.tenantid`

	// Filters
	var params []interface{}
	q1 = baseWithTenant

	if tid != 0 {
		q1 += " WHERE o.tenantid = ?"
		params = append(params, tid)
	} else if pid != 0 {
		q1 += " WHERE o.partnerid = ?"
		params = append(params, pid)
	} else if cid != 0 {
		q1 += " WHERE o.customerid = ?"
		params = append(params, cid)
	} else if lid != 0 {
		q1 += " WHERE o.locationid = ?"
		params = append(params, lid)
	} else {
		q1 += " WHERE 1=1"
	}

	if fdate != "" && tdate != "" {
		q1 += " AND o.orderdate::date BETWEEN ?::date AND ?::date"
		params = append(params, fdate, tdate)
	}

	// 👇 group by tenantid & tenantname
	q1 += ` GROUP BY t.tenantid, t.tenantname`

	utils.Logger.Debugf("Query: %s", q1)

	if err := db.DB.Raw(q1, params...).Scan(&data).Error; err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}

func GetLocationOrderSummaryDaily(c *fiber.Ctx) error {
	tenantIDStr := c.Query("tenantid")
	tenantID, _ := strconv.Atoi(tenantIDStr)

	var data []models.Ordersummarylocation
	var q1 string
	var params []interface{}

	q1 = `
		SELECT 
			l.locationid, l.locationname, 
			COALESCE(COUNT(o.orderid), 0) AS total,
			COALESCE(SUM(CASE WHEN o.orderstatus = 'created' THEN 1 ELSE 0 END), 0) AS created,
			COALESCE(SUM(CASE WHEN o.orderstatus = 'pending' THEN 1 ELSE 0 END), 0) AS pending,
			COALESCE(SUM(CASE WHEN o.orderstatus = 'processing' THEN 1 ELSE 0 END), 0) AS processing,
			COALESCE(SUM(CASE WHEN o.orderstatus = 'delivered' THEN 1 ELSE 0 END), 0) AS delivered,
			COALESCE(SUM(CASE WHEN o.orderstatus = 'cancelled' THEN 1 ELSE 0 END), 0) AS cancelled
		FROM tenantlocations l
		LEFT JOIN orders o 
			ON l.locationid = o.locationid 
			AND l.tenantid = o.tenantid
	`

	if tenantID != 0 {
		q1 += " WHERE l.tenantid = ?"
		params = append(params, tenantID)
	}

	q1 += " GROUP BY l.locationid, l.locationname ORDER BY l.locationid"

	if err := db.DB.Raw(q1, params...).Scan(&data).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}

func GetCustomerOrderByLocation(c *fiber.Ctx) error {
	cid, _ := strconv.Atoi(c.Query("customerid"))

	result, err := domain.GetCustomerOrderByLocation(cid)
	if err != nil {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"details": []interface{}{}, // return [] on error
		})
	}

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})
}
