package controllers

import (
	"fmt"
	"math"
	"strconv"
	"time"
	"zatobay_api/database"
	"zatobay_api/models"

	"github.com/gofiber/fiber/v2"

	datatable "zatobay_api/utils/datatable"
)

type FilterAjaxBan struct {
	Code    string `json:"code" url:"code" query:"code"`
	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 CreateBan(c *fiber.Ctx) error {

	// user auth

	var data map[string]string

	if err := c.BodyParser(&data); err != nil {
		return c.Status(400).JSON(err.Error())
	}
	ban_category_id, err := strconv.Atoi(data["ban_category_id"])
	if err != nil {
		return err
	}

	ban_info := models.Ban{
		BanCategoryId: ban_category_id,
		Code:          data["code"],
		Status:        "1",
		CreatedAt:     time.Now(),
		UpdatedAt:     time.Now(),
	}

	res := database.DB.Create(&ban_info)
	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",
		"data":   ban_info,
	})
}

func GetBan(c *fiber.Ctx) error {

	var ban_info []models.Ban

	result := database.DB.Find(&ban_info)

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

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

func GetBanById(c *fiber.Ctx) error {

	var ban_info models.Ban

	paramsId := c.Params("id")

	id_int, err := strconv.Atoi(paramsId)

	if err != nil {
		return err
	}

	result := database.DB.Find(&ban_info, id_int)

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

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

func GetBanByBanCategoryId(c *fiber.Ctx) error {

	var ban_info []models.Ban

	paramsId := c.Params("id")

	ban_category_id_int, err := strconv.Atoi(paramsId)

	if err != nil {
		return err
	}

	result := database.DB.Where("ban_category_id = ?", ban_category_id_int).Order("status desc").Find(&ban_info)
	if result.RowsAffected == 0 {
		return c.Status(200).JSON(fiber.Map{
			"status": "empty ban",
			"data":   ban_info,
		})
	}

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

func UpdateBan(c *fiber.Ctx) error {
	var data map[string]string

	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
	}

	ban_info := models.Ban{
		Code:      data["code"],
		Status:    data["status"],
		UpdatedAt: time.Now(),
	}

	ban_result := models.Ban{}

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

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

	res_ban := database.DB.Where("id = ?", id_int).Find(&ban_result)
	if res_ban.RowsAffected == 0 {
		return c.Status(404).JSON(fiber.Map{
			"status": "empty ban",
		})
	}

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

func DeleteBan(c *fiber.Ctx) error {

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

	if err != nil {
		id_int = -1
	}

	var Ban models.Ban

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

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

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

func BanAjaxListByBanCategoryId(c *fiber.Ctx) error {

	filterAjax := new(FilterAjaxBan)

	ban_category_id_int, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return err
	}

	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
	}

	Ban := models.Ban{
		Code: filterAjax.Code,
	}

	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 := BanQueryAjaxList(Ban, limit, offset, sort, ban_category_id_int)

	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 dataResponseBan []models.Ban

		for _, data := range data {
			dataResponseBan = append(dataResponseBan, data)
		}

		datatableFormat.Data = dataResponseBan
		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 BanQueryAjaxList(filter models.Ban, limit, offset int, sort map[string]string, ban_category_id_int int) ([]models.Ban, *int64, error) {
	var (
		result []models.Ban
		count  int64
	)

	query := database.DB.Where(filter).Where("ban_category_id = ?", ban_category_id_int)
	fmt.Println(filter.Code)
	fmt.Println(filter)
	if filter.Code == "" {
		query = database.DB.Where(filter).Where("ban_category_id = ?", ban_category_id_int)
	} else {
		query = database.DB.Where("code LIKE ?", "%"+filter.Code+"%").Where("ban_category_id = ?", ban_category_id_int)
	}

	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).Find(&result)
	fmt.Println(query)
	if query.Error != nil {
		return nil, nil, query.Error
	}
	dbCount := database.DB.Table("bans").Where(filter).Select("id").Count(&count)
	if dbCount.Error != nil {
		return nil, nil, dbCount.Error
	}
	return result, &count, nil

}
