package controllers

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

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

func CreateCustomer(c *fiber.Ctx) error {

	var data models.Customers
	var id int

	if err := c.BodyParser(&data); err != nil {
		utils.Error("CreateCustomer body parse error", "error", err)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": err.Error(),
			"status":  false,
		})
	}

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

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

		data.Customerid = cid

		tcid := domain.CheckTenantCustomer(data.Customerid, data.Tenantid)
		if tcid == 0 {

			id = domain.CreateTenantCustomer(data)

		} else {

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

		}

	} else {

		id = domain.CreateCustomer(data)

	}

	if id != 0 {

		result := domain.GetCustomer(id, "")
		return c.JSON(fiber.Map{
			"status":  true,
			"code":    http.StatusCreated,
			"message": "Successful",
			"details": result,
		})

	} else {

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

	}

}

func UpdateCustomer(c *fiber.Ctx) error {

	var data models.Customers

	if err := c.BodyParser(&data); err != nil {
		utils.Error("UpdateCustomer body parse error", "error", err)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": err.Error(),
			"status":  false,
		})
	}

	result := domain.UpdateCustomer(data)

	if !result.Status {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": "Failed",
		})

	}

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

}

func GetCustomer(c *fiber.Ctx) error {

	cid, _ := strconv.Atoi(c.Query("customerid"))
	cno := c.Query("contactno")

	result := domain.GetCustomer(cid, cno)

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

}

func GetTenantCustomers(c *fiber.Ctx) error {
	tid, _ := strconv.Atoi(c.Query("tenantid"))
	lid, _ := strconv.Atoi(c.Query("locationid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	keyword := c.Query("keyword") 

	result := domain.GetTenantCustomers(tid, lid, aid, pageno, pagesize, keyword)

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

func GetCustomersbytenent(c *fiber.Ctx) error {

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

	//aid, _ := strconv.Atoi(c.Query("applocationid"))

	result := domain.GetCustomerbytenant(tid, lid)

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

}

func GetCustomersbyapplocation(c *fiber.Ctx) error {

	tid, _ := strconv.Atoi(c.Query("applocationid"))

	result := domain.GetCustomerbyApplocation(tid)

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

}

func GetallCustomers(c *fiber.Ctx) error {
	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	keyword := c.Query("keyword") // <-- new param

	result := domain.GetallCustomers(aid, pageno, pagesize, keyword)

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

func SearchCustomer(c *fiber.Ctx) error {

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

	result := domain.SearchCustomer(keyword, tid)

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

}

func DeleteCustomer(c *fiber.Ctx) error {

	cid, _ := strconv.Atoi(c.Query("customerid"))

	count := GetCustomerOrderCount(cid)

	if count == 0 {

		tx := db.DB.Begin()
		t1 := tx.Table("customers").Where("customerid = ?", cid).Delete(&models.Customers{})
		if t1.Error != nil {
			utils.Error("DeleteCustomer t1 delete error", "error", t1.Error)
			tx.Rollback()
			return c.JSON(fiber.Map{
				"code":    http.StatusInternalServerError,
				"message": "Error deleting customer",
				"status":  false,
			})
		}

		t2 := tx.Table("customerlocations").Where("customerid = ?", cid).Delete(&models.Customerlocations{})
		if t2.Error != nil {
			utils.Error("DeleteCustomer t2 delete error", "error", t2.Error)
			tx.Rollback()
			return c.JSON(fiber.Map{
				"code":    http.StatusInternalServerError,
				"message": "Error deleting customer",
				"status":  false,
			})
		}

		t3 := tx.Table("tenantcustomers").Where("customerid = ?", cid).Delete(&models.Tenantcustomers{})
		if t3.Error != nil {
			utils.Error("DeleteCustomer t3 delete error", "error", t3.Error)
			tx.Rollback()
			return c.JSON(fiber.Map{
				"code":    http.StatusInternalServerError,
				"message": "Error deleting customer",
				"status":  false,
			})
		}

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

	}

	return c.JSON(fiber.Map{
		"code":    http.StatusConflict,
		"message": "Orders available for customers",
		"status":  false,
	})

}

func CreateCustomerLocation(c *fiber.Ctx) error {

	var data models.Customerlocations

	if err := c.BodyParser(&data); err != nil {
		utils.Error("CreateCustomerLocation body parse error", "error", err)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": err.Error(),
			"status":  false,
		})
	}

	id := domain.CreateCustomerLocation(data)
	if id != 0 {

		result := domain.GetCustomerLocation(id)
		return c.JSON(result)

	} else {

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

	}

}

func GetCustomerLocations(c *fiber.Ctx) error {

	cid, _ := strconv.Atoi(c.Query("customerid"))

	result := domain.GetCustomerLocation(cid)
	return c.JSON(result)

}

func CreateCustomerRequest(c *fiber.Ctx) error {
	var req models.CustomerRequest

	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    400,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	now := time.Now()
	req.Created = now
	req.Updated = now

	// Insert into database
	if err := db.DB.Table("customerrequest").Create(&req).Error; err != nil {
		utils.Error("CreateCustomerRequest DB error", "error", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"code":    500,
			"message": "Failed to create customer request",
			"status":  false,
		})
	}

	return c.Status(fiber.StatusCreated).JSON(fiber.Map{
		"code":    201,
		"message": "Customer request created successfully",
		"status":  true,
		"data":    req,
	})
}

func GetCustomerRequests(c *fiber.Ctx) error {
	customerIDStr := c.Query("customerid")
	pageNoStr := c.Query("pageno", "1")
	pageSizeStr := c.Query("pagesize", "10")

	pageNo, _ := strconv.Atoi(pageNoStr)
	pageSize, _ := strconv.Atoi(pageSizeStr)

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

	var requests []models.CustomerRequest
	query := db.DB.Table("customerrequest")

	// Optional filter by customerid
	if customerIDStr != "" {
		customerID, err := strconv.Atoi(customerIDStr)
		if err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
				"code":    400,
				"message": "Invalid customerid",
				"status":  false,
			})
		}
		if customerID != 0 {
			query = query.Where("customerid = ?", customerID)
		}
	}

	var total int64
	query.Count(&total)

	if err := query.Order("created desc").Offset(offset).Limit(pageSize).Find(&requests).Error; err != nil {
		utils.Error("GetCustomerRequests DB error", "error", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"code":    500,
			"message": "Failed to fetch customer requests",
			"status":  false,
		})
	}

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

func GetCustomerSummary(c *fiber.Ctx) error {
	aid, _ := strconv.Atoi(c.Query("applocationid", "0"))
	tid, _ := strconv.Atoi(c.Query("tenantid", "0"))

	// Initialize query builder
	query := db.DB.Table("customers as a").
		Joins("INNER JOIN customerlocations b ON a.customerid = b.customerid").
		Where("b.primaryaddress = 1")

	if aid != 0 {
		query = query.Where("a.applocationid = ?", aid)
	}

	if tid != 0 {
		query = query.Joins("INNER JOIN tenantcustomers ct ON a.customerid = ct.customerid").
			Where("ct.tenantid = ?", tid)
	}

	type Summary struct {
		Total    int64
		Active   int64
		Inactive int64
	}

	var summary Summary

	// Execute consolidated summary counts
	err := query.Select(`
		COUNT(DISTINCT a.customerid) AS total,
		COUNT(DISTINCT CASE WHEN a.status = 0 THEN a.customerid END) AS active,
		COUNT(DISTINCT CASE WHEN a.status = 1 THEN a.customerid END) AS inactive`).
		Scan(&summary).Error

	if err != nil {
		utils.Error("GetCustomerSummary DB error", "error", err)
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Failed to fetch customer summary",
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Customer summary fetched successfully",
		"status":  true,
		"summary": summary,
	})
}
