package controllers

import (
	"fmt"
	"math"
	"strconv"
	"zatobay_api/database"
	"zatobay_api/models"
	"zatobay_api/utils/datatable"

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

type FilterAjaxLoker struct {
	Code    string `json:"code" url:"code" query:"code"`
	Status  string `json:"status" url:"status" query:"status"`
	Page    string `json:"page" url:"page" query:"page"`
	PerPage string `json:"length" url:"length" query:"length"`
	Sort    string `json:"column" url:"column" query:"column"`
	SortDir string `json:"dir" url:"dir" query:"dir"`
	Draw    string `json:"draw" url:"draw" query:"draw"`
}

func CreateLoker(c *fiber.Ctx) error {

	data := new(models.Loker)

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

	var category models.LokerCategory

	if data.CategoryLokerId == 0 {
		resultCategory := database.DB.Where(models.LokerCategory{Name: "default"}).FirstOrCreate(&category)
		if resultCategory.RowsAffected != 0 {
			data.CategoryLokerId = int(category.Id)
		} else {
			findDefaultCategory := database.DB.Where("name = ?", "default").First(&category)
			if findDefaultCategory.Error != nil {
				return c.Status(400).JSON(fiber.Map{
					"status": "error, default category loker not found",
					"error":  findDefaultCategory.Error,
				})
			}
		}
	} else {
		result := database.DB.First(&category, data.CategoryLokerId)
		if result.Error != nil {
			return c.Status(400).JSON(fiber.Map{
				"status": "error, category loker not found",
				"error":  result.Error,
			})
		}
	}

	data.CategoryLoker = category
	data.CategoryLokerId = int(category.Id)
	data.Status = "1"

	res := database.DB.Create(&data)

	if res.Error != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "error",
			"error":  res.Error,
		})
	}
	return c.Status(200).JSON(fiber.Map{
		"status": "success create loker",
		"data":   data,
	})

}

func GetLoker(c *fiber.Ctx) error {

	var data []models.Loker

	result := database.DB.Preload("CategoryLoker").Find(&data)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   data,
	})
}

func GetLokerOrderByAvailability(c *fiber.Ctx) error {

	var data []models.Loker

	result := database.DB.Order("status asc").Preload("CategoryLoker").Find(&data)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	var dataResponse []models.ResponseLokerWithoutCategory

	for _, data := range data {
		dataResponse = append(dataResponse, *data.ToResponse())
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   dataResponse,
	})
}

func GetLokerById(c *fiber.Ctx) error {

	var data models.Loker

	paramsId := c.Params("id")

	id_int, err := strconv.Atoi(paramsId)

	if err != nil {
		return err
	}

	result := database.DB.Preload("CategoryLoker").First(&data, id_int)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   data,
	})
}

func GetLokerByCategoryId(c *fiber.Ctx) error {

	var data []models.Loker

	paramsId := c.Params("id")

	id_int, err := strconv.Atoi(paramsId)

	if err != nil {
		return err
	}

	result := database.DB.Where("category_loker_id = ?", id_int).Find(&data)
	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   models.ToLokerResponses(data),
	})
}

func UpdateLoker(c *fiber.Ctx) error {
	data := new(models.Loker)

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

	id := c.Params("id")
	id_int, err := strconv.Atoi(id)

	if err != nil {
		return err
	}

	result := database.DB.Where("id = ?", id_int).Updates(data)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	var updatedData models.Loker
	resultUpdate := database.DB.Preload("CategoryLoker").First(&updatedData, id_int)
	if resultUpdate.Error != nil {
		return c.Status(400).JSON(err.Error())
	}

	return c.Status(200).JSON(fiber.Map{
		"message": "success update loker, id :" + id,
		"data":    updatedData,
		"status":  "success",
	})
}

func GetPrice(c *fiber.Ctx) error {

	var category models.LokerCategory

	findDefaultCategory := database.DB.Where("name = ?", "default").First(&category)

	if findDefaultCategory.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"price":  category.Price,
	})
}

func UpdatePrice(c *fiber.Ctx) error {
	data := new(models.LokerCategory)

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

	var category models.LokerCategory

	findDefaultCategory := database.DB.Where("name = ?", "default").First(&category)
	if findDefaultCategory.Error != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "error, default category loker not found",
			"error":  findDefaultCategory.Error,
		})
	}

	result := database.DB.Where("id = ?", category.Id).Updates(data)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	var updatedData models.LokerCategory
	resultUpdate := database.DB.First(&updatedData, category.Id)
	if resultUpdate.Error != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "error, error update",
			"error":  result.Error,
		})
	}

	return c.Status(200).JSON(fiber.Map{
		"message": "success update harga",
		"harga":   updatedData.Price,
		"status":  "success",
	})
}

func DeleteLoker(c *fiber.Ctx) error {

	id := c.Params("id")
	id_int, err := strconv.Atoi(id)

	if err != nil {
		id_int = -1
	}

	var data models.Loker

	result := database.DB.Delete(&data, id_int)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"message": "success delete loker, id :" + id,
		"status":  "success",
	})
}

//
//func LokerAjaxListByCategory(c *fiber.Ctx) error {
//
//	paramsId := c.Params("id")
//
//	id_int, err := strconv.Atoi(paramsId)
//
//	if err != nil {
//		return err
//	}
//
//	filterAjax := new(FilterAjaxLoker)
//	filterAjax.Category = id_int
//
//	if err := c.QueryParser(filterAjax); err != nil {
//		return c.Status(400).JSON(err.Error())
//	}
//
//	page, err := strconv.Atoi(filterAjax.Page)
//	if err != nil {
//		page = 1
//	}
//	perPage, err := strconv.Atoi(filterAjax.PerPage)
//	if err != nil {
//		perPage = 10
//	}
//
//	Loker := models.Loker{
//		Code:            filterAjax.Code,
//		Status:          filterAjax.Status,
//		CategoryLokerId: filterAjax.Category,
//	}
//
//	var sort map[string]string
//	sort = make(map[string]string)
//	if filterAjax.Sort != "" {
//		if filterAjax.SortDir == "" {
//			sort[filterAjax.Sort] = "desc"
//		} else {
//			sort[filterAjax.Sort] = filterAjax.SortDir
//		}
//	}
//	limit := perPage
//	offset := (page - 1) * limit
//
//	data, total, err := LokerQueryAjaxList(Loker, limit, offset, sort)
//
//	if err != nil {
//		return c.Status(400).JSON(err.Error())
//	}
//	pages := math.Ceil(float64(*total) / float64(perPage))
//	meta := datatable.MetaDataTable{
//		CurrentPage: page,
//		From:        offset + 1,
//		LastPage:    int(pages),
//		Path:        "",
//		PerPage:     fmt.Sprintf("%v", limit),
//		To:          offset + limit,
//		Total:       int(*total),
//	}
//
//	datatableFormat := datatable.DataTable{
//		Meta: datatable.MetaDataTable{
//			CurrentPage: page,
//			From:        0,
//			LastPage:    1,
//			Path:        *datatable.BuildUrlForLink(c.Request(), 0),
//			PerPage:     strconv.Itoa(perPage),
//			To:          0,
//			Total:       0,
//		},
//		Data: nil,
//		Links: datatable.LinkDatatable{
//			First: *datatable.BuildUrlForLink(c.Request(), 1),
//			Last:  nil,
//			Next:  nil,
//			Prev:  nil,
//		},
//		Payload: filterAjax,
//	}
//
//	if err == nil {
//		var dataResponse []models.ResponseLokerWithoutCategory
//
//		for _, data := range data {
//			dataResponse = append(dataResponse, *data.ToResponse())
//		}
//
//		datatableFormat.Data = dataResponse
//		meta.Path = *datatable.BuildUrlForLink(c.Request(), 0)
//		datatableFormat.Meta = meta
//		datatableFormat.Links = datatable.BuildLinksData(c.Request(), meta)
//	}
//
//	return c.JSON(fiber.Map{
//		"status": "success",
//		"data":   datatableFormat,
//	})
//}

func LokerAjaxList(c *fiber.Ctx) error {

	filterAjax := new(FilterAjaxLoker)

	if err := c.QueryParser(filterAjax); err != nil {
		return c.Status(400).JSON(err.Error())
	}

	page, err := strconv.Atoi(filterAjax.Page)
	if err != nil {
		page = 1
	}
	perPage, err := strconv.Atoi(filterAjax.PerPage)
	if err != nil {
		perPage = 10
	}

	Loker := models.Loker{
		Code:   filterAjax.Code,
		Status: filterAjax.Status,
	}

	var sort map[string]string
	sort = make(map[string]string)
	if filterAjax.Sort != "" {
		if filterAjax.SortDir == "" {
			sort[filterAjax.Sort] = "desc"
		} else {
			sort[filterAjax.Sort] = filterAjax.SortDir
		}
	}
	limit := perPage
	offset := (page - 1) * limit

	data, total, err := LokerQueryAjaxList(Loker, limit, offset, sort)

	if err != nil {
		return c.Status(400).JSON(err.Error())
	}
	pages := math.Ceil(float64(*total) / float64(perPage))
	meta := datatable.MetaDataTable{
		CurrentPage: page,
		From:        offset + 1,
		LastPage:    int(pages),
		Path:        "",
		PerPage:     fmt.Sprintf("%v", limit),
		To:          offset + limit,
		Total:       int(*total),
	}

	datatableFormat := datatable.DataTable{
		Meta: datatable.MetaDataTable{
			CurrentPage: page,
			From:        0,
			LastPage:    1,
			Path:        *datatable.BuildUrlForLink(c.Request(), 0),
			PerPage:     strconv.Itoa(perPage),
			To:          0,
			Total:       0,
		},
		Data: nil,
		Links: datatable.LinkDatatable{
			First: *datatable.BuildUrlForLink(c.Request(), 1),
			Last:  nil,
			Next:  nil,
			Prev:  nil,
		},
		Payload: filterAjax,
	}

	if err == nil {
		var dataResponse []models.ResponseLokerWithoutCategory

		for _, data := range data {
			dataResponse = append(dataResponse, *data.ToResponse())
		}

		datatableFormat.Data = dataResponse
		meta.Path = *datatable.BuildUrlForLink(c.Request(), 0)
		datatableFormat.Meta = meta
		datatableFormat.Links = datatable.BuildLinksData(c.Request(), meta)
	}

	return c.JSON(fiber.Map{
		"status": "success",
		"data":   datatableFormat,
	})
}

func LokerQueryAjaxList(filter models.Loker, limit, offset int, sort map[string]string) ([]models.Loker, *int64, error) {
	var (
		result []models.Loker
		count  int64
	)

	query := database.DB.Where(filter)
	if filter.Code == "" {
		query = database.DB.Where(filter)
	} else {
		query = database.DB.Where("code LIKE ?", "%"+filter.Code+"%")
	}
	if sort == nil {
		query = query.Order("id")
	} else {
		for key, val := range sort {
			query = query.Order(fmt.Sprintf("%s %s", key, val))
		}
	}
	query = query.Offset(offset).Limit(limit).Preload("CategoryLoker").Find(&result)
	fmt.Println(query)
	if query.Error != nil {
		return nil, nil, query.Error
	}
	dbCount := database.DB.Table("lokers").Where(filter).Select("id").Count(&count)
	if dbCount.Error != nil {
		return nil, nil, dbCount.Error
	}
	return result, &count, nil

}
