package controllers

import (
	"net/http"
	"strconv"

	"nearle/models"
	"nearle/services"

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

type ProductController struct {
	productService services.ProductService
}

func NewProductController(productService services.ProductService) *ProductController {
	return &ProductController{productService: productService}
}

func (ctl *ProductController) GetProductSubCategory(c *fiber.Ctx) error {
	categoryID, _ := strconv.Atoi(c.Query("categoryid", "0"))
	tenantID, _ := strconv.Atoi(c.Query("tenantid", "0"))

	data, err := ctl.productService.GetProductSubCategory(categoryID, tenantID)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

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

func (ctl *ProductController) GetProductCount(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	categoryID, _ := strconv.Atoi(c.Query("categoryid"))
	subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
	// locationID, _ := strconv.Atoi(c.Query("locationid"))
	approve := c.Query("approve", "")

	data, err := ctl.productService.GetProductCount(tenantID, categoryID, subcategoryID, approve)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": "failed",
			"status":  false,
		})
	}

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

func (ctl *ProductController) GetProductCategory(c *fiber.Ctx) error {
	data, err := ctl.productService.GetProductCategory()
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    500,
			"message": "Failed to fetch categories",
			"status":  false,
		})
	}

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

func (ctl *ProductController) GetProductVariants(c *fiber.Ctx) error {

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

	data, err := ctl.productService.GetProductVariants(tenantID, subcategoryID)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    500,
			"message": "Failed to fetch Product varients",
			"status":  false,
		})
	}

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

func (ctl *ProductController) GetCatalougeProducts(c *fiber.Ctx) error {

	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	locationID, _ := strconv.Atoi(c.Query("locationid"))
	subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
	keyword := c.Query("keyword")
	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))

	data, err := ctl.productService.GetCatalougeProducts(tenantID, locationID, subcategoryID, pageno, pagesize, keyword)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    500,
			"message": "Failed to fetch Catalouge Product",
			"status":  false,
		})
	}

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

}

func (ctl *ProductController) GetProductStocks(c *fiber.Ctx) error {
	tenantID := c.Query("tenantid")
	locationID := c.Query("locationid")

	stocks, err := ctl.productService.GetProductStocks(tenantID, locationID)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    500,
			"message": "Failed to fetch product stocks",
			"status":  false,
		})
	}

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

func (ctl *ProductController) CreateProductStock(c *fiber.Ctx) error {
	var stocks []models.Productstock

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

	if err := ctl.productService.CreateProductStock(stocks); err != nil {
		return c.JSON(fiber.Map{
			"code":    500,
			"message": "Failed to create product stocks",
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    201,
		"message": "Product stocks created successfully",
		"status":  true,
		"details": stocks,
	})
}

func (ctl *ProductController) CreateProduct(c *fiber.Ctx) error {
	var product models.Products

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

	if err := ctl.productService.CreateProduct(product); err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": "Failed to create product",
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusCreated,
		"message": "Product created successfully",
		"status":  true,
		"data":    product,
	})
}

func (ctl *ProductController) UpdateProduct(c *fiber.Ctx) error {
	var product models.Products

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

	if err := ctl.productService.UpdateProduct(product); err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

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

func (ctl *ProductController) DeleteProduct(c *fiber.Ctx) error {

	pidStr := c.Query("productid")
	pid, err := strconv.Atoi(pidStr)
	if err != nil || pid <= 0 {
		return c.JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid product ID",
			"status":  false,
		})
	}

	if err := ctl.productService.DeleteProduct(pid); err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

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

func (ctl *ProductController) GetStockStatement(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	locationID, _ := strconv.Atoi(c.Query("locationid"))
	subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))
	keyword := c.Query("keyword")

	data, err := ctl.productService.GetStockStatement(tenantID, locationID, subcategoryID, pageno, pagesize, keyword)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

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

func (ctl *ProductController) GetLocationProducts(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	locationID, _ := strconv.Atoi(c.Query("locationid"))
	subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
	keyword := c.Query("keyword")
	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))

	result, err := ctl.productService.GetLocationProducts(tenantID, locationID, subcategoryID, pageno, pagesize, keyword)
	if err != nil {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
		})
	}

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

// GetSaleTemplate serves the data the web app turns into the offline-sales
// spreadsheet.
//
// locationid is optional and defaults to 0, meaning every branch the tenant
// runs — one workbook for the whole business, with each row carrying the branch
// its stock belongs to. A store user passes their own locationid to get just
// theirs. tenantid is required: without it there is no scope at all.
func (ctl *ProductController) GetSaleTemplate(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	locationID, _ := strconv.Atoi(c.Query("locationid", "0"))

	if tenantID <= 0 {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusBadRequest,
			"message": "tenantid is required",
		})
	}

	result, err := ctl.productService.GetSaleTemplate(tenantID, locationID)
	if err != nil {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
		})
	}

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

func (ctl *ProductController) GetLocationProductSummary(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	locationID, _ := strconv.Atoi(c.Query("locationid"))

	result, err := ctl.productService.GetLocationProductSummary(tenantID, locationID)
	if err != nil {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
		})
	}

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

func (ctl *ProductController) GetAllProducts(c *fiber.Ctx) error {
	categoryID, _ := strconv.Atoi(c.Query("categoryid"))
	subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
	productID, _ := strconv.Atoi(c.Query("productid"))
	applocationID, _ := strconv.Atoi(c.Query("applocationid"))
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	locationID, _ := strconv.Atoi(c.Query("locationid"))
	keyword := c.Query("keyword", "")
	productStatus := c.Query("productstatus", "")
	approve := c.Query("approve", "")
	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))

	details, err := ctl.productService.FetchFilteredProducts(
		categoryID, subcategoryID, productID, applocationID, tenantID,
		locationID, keyword, productStatus, approve, pageno, pagesize,
	)
	if err != nil {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": err.Error(),
		})
	}

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

func (ctl *ProductController) GetProductByVariant(c *fiber.Ctx) error {

	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	variantid, _ := strconv.Atoi(c.Query("variantid"))
	locationID, _ := strconv.Atoi(c.Query("locationid"))

	result, err := ctl.productService.GetProductByVariant(tenantID, variantid, locationID)

	if err != nil {

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

	}

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

}

func (ctl *ProductController) GetProductsBySubcategory(c *fiber.Ctx) error {
	categoryID, err := strconv.Atoi(c.Query("categoryid"))
	if err != nil || categoryID == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    400,
			"status":  false,
			"message": "Valid categoryid is required",
			"data":    fiber.Map{},
		})
	}

	params := models.ProductFilter{
		CategoryID:    categoryID,
		TenantID:      parseInt(c.Query("tenantid")),
		AppLocationID: parseInt(c.Query("applocationid")),
		ProductID:     parseInt(c.Query("productid")),
		Keyword:       c.Query("keyword"),
		LocationID:    parseInt(c.Query("locationid")),
	}

	result, err := ctl.productService.GetProductsBySubcategory(params)
	if err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    500,
			"status":  false,
			"message": err.Error(),
			"data":    fiber.Map{},
		})
	}

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

func parseInt(s string) int {
	if s == "" {
		return 0
	}
	val, _ := strconv.Atoi(s)
	return val
}

func (ctl *ProductController) UpdateProductLocation(c *fiber.Ctx) error {
	var data models.Productlocations

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

	if err := ctl.productService.UpdateProductLocation(data); err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": err.Error(),
		})
	}

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

func (ctl *ProductController) CreateProductLocation(c *fiber.Ctx) error {
	var data []models.Productlocations

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

	if err := ctl.productService.CreateProductLocation(data); err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": err.Error(),
		})
	}

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

func (ctl *ProductController) CreateProductVariant(c *fiber.Ctx) error {
	var input models.Productvariant

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

	// Call service layer
	if err := ctl.productService.CreateProductVariant(input); err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

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

func (ctl *ProductController) ImportCatalogueProduct(c *fiber.Ctx) error {
	var data []models.ImportCatalogueProductRequest

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

	if len(data) == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Request body must contain at least one product",
			"status":  false,
		})
	}

	for _, req := range data {
		if req.Tenantid == 0 || req.Locationid == 0 || req.Brand == "" || req.Catalogueid == 0 || req.Categoryid == 0 {
			return c.Status(http.StatusBadRequest).JSON(fiber.Map{
				"code":    http.StatusBadRequest,
				"message": "tenantid, locationid, brand, catalogueid, and categoryid are required",
				"status":  false,
			})
		}
	}

	if err := ctl.productService.ImportCatalogueProduct(data); err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": err.Error(),
		})
	}

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

func (ctl *ProductController) GetImportedCatalogueProducts(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	// brand is optional: omit it to check imported status across every
	// brand at once, matching the all-brands catalogue browse view.
	brand := c.Query("brand")

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

	refs, err := ctl.productService.GetImportedCatalogueRefs(tenantID, brand)
	if err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

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

func (ctl *ProductController) GetTenantCategories(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenantid"))
	if tenantID == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "tenantid is required",
			"status":  false,
		})
	}

	categories, err := ctl.productService.GetTenantCategories(tenantID)
	if err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

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

func (ctl *ProductController) DeleteProductLocation(c *fiber.Ctx) error {
	var input struct {
		Tenantid   int `json:"tenantid"`
		Locationid int `json:"locationid"`
		Productid  int `json:"productid"`
	}

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

	if input.Tenantid == 0 || input.Locationid == 0 || input.Productid == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "tenantid, locationid, and productid are required",
			"status":  false,
		})
	}

	if err := ctl.productService.DeleteProductLocation(input.Tenantid, input.Locationid, input.Productid); err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.Status(http.StatusOK).JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Product location deleted successfully",
		"status":  true,
	})
}
