package controllers

import (
	"encoding/csv"
	"errors"
	"fmt"
	"log"
	"math"
	"os"
	"strconv"
	"time"
	"zatobay_api/database"
	"zatobay_api/models"
	datatable "zatobay_api/utils/datatable"

	"github.com/gofiber/fiber/v2"
	strftime "github.com/itchyny/timefmt-go"
	"github.com/jung-kurt/gofpdf"
	"github.com/leekchan/accounting"
	"gorm.io/gorm"
)

type FilterAjaxOrderBan struct {
	CategoryBan string `json:"category_ban" url:"category_ban" query:"category_ban"`
	CodeBan     string `json:"code_ban" url:"code_ban" query:"code_ban"`
	StartDate   string `json:"start_date" url:"start_date" query:"start_date"`
	EndDate     string `json:"end_date" url:"end_date" query:"end_date"`
	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"`
}

type FilterDateRangeOrderBan struct {
	CodeBan   string `json:"code_ban" url:"code_ban" query:"code_ban"`
	StartDate string `json:"start_date" url:"start_date" query:"start_date"`
	EndDate   string `json:"end_date" url:"end_date" query:"end_date"`
}

func CreateOrderBan(c *fiber.Ctx) error {

	var nama_kasir string

	current_time := time.Now()
	curr_time := strftime.Format(current_time, "%Y%m%d%H%M%S")

	type IncomingData struct {
		OrderBan []struct {
			Id int `json:"id"`
		} `json:"order_ban"`
		PenyewaBan string `json:"penyewa"`
	}

	data := IncomingData{}

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

	// get nama kasir
	if c.Get("Authorization") == "" {
		return c.JSON(fiber.Map{
			"message": "Auth Token must be set",
		})
	}

	err, id_kasir, nama_kasir := GetNamaKasir(c.Get("Authorization"))
	_, err_id_kasir := strconv.Atoi(id_kasir)

	if err_id_kasir != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "cannot convert cashier id",
		})
	}

	if err != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "Error get cashier name",
		})
	}

	if err_id_kasir != nil {
		return err_id_kasir
	}

	// get ban price
	type Result struct {
		BanCategoryId int64  `json:"ban_category_id"`
		Code          string `json:"code"`
	}
	var results Result

	type IdBan struct {
		Id string `json:"id"`
	}

	type PriceBan struct {
		Price string `json:"price"`
	}

	type OrderBanTemp struct {
		IdBan int    `json:"id_ban"`
		Code  string `json:"code"`
		Price int    `json:"price"`
	}

	var temp []OrderBanTemp

	var PriceBans PriceBan

	var ban_category_id []int64

	for _, x := range data.OrderBan {
		ban := database.DB.Table("bans").Where("id= ?", x.Id).First(&results)
		fmt.Println(results)
		if ban.Error != nil {
			return c.Status(400).JSON(fiber.Map{
				"status": "Ban Tidak Ditemukan",
				"Error":  ban.Error,
			})
		}
		database.DB.Table("ban_categories").Where("id= ?", results.BanCategoryId).Find(&PriceBans)
		ban_category_id = append(ban_category_id, results.BanCategoryId)
		if PriceBans.Price == "" {
			PriceBans.Price = "0"
		}
		price_ban_int, err := strconv.Atoi(PriceBans.Price)
		if err != nil {
			return c.Status(400).JSON(fiber.Map{
				"status": "cannot convert price",
			})
		}

		temp = append(temp, OrderBanTemp{x.Id, results.Code, price_ban_int})

	}

	fmt.Println(temp)

	// get price_total
	var price_total int64

	for _, y := range temp {

		price_total += int64(y.Price)
	}
	fmt.Println(price_total)

	// declare order_id
	order_id := "BAN" + curr_time

	OrderBan := models.OrdersBan{
		OrderId:    order_id,
		Trxdate:    time.Now(),
		NamaAdmin:  nama_kasir,
		Quantity:   len(data.OrderBan),
		Penyewa:    data.PenyewaBan,
		PriceTotal: int(price_total),
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
	}

	create_order_ban := database.DB.Create(&OrderBan)
	if create_order_ban.Error != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "Error",
			"Error":  create_order_ban.Error,
		})
	}

	// create order ban details

	var OrderBanDetailArr []models.OrdersBanDetail

	for _, y := range temp {
		OrderBanDetail := models.OrdersBanDetail{
			OrderId:    order_id,
			IdBan:      y.IdBan,
			CodeBan:    y.Code,
			PriceTotal: y.Price,
			CreatedAt:  time.Now(),
			UpdatedAt:  time.Now(),
		}

		OrderBanDetailArr = append(OrderBanDetailArr, OrderBanDetail)
	}

	create_order_ban_detail := database.DB.Create(&OrderBanDetailArr)
	if create_order_ban_detail.Error != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "Error",
			"Error":  create_order_ban_detail.Error,
		})
	}

	// update status ban when purchased
	ban_info := models.Ban{
		Status:    "0",
		UpdatedAt: time.Now(),
	}

	for _, updt := range temp {

		if err != nil {
			return err
		}
		database.DB.Where("id = ?", updt.IdBan).Updates(&ban_info)
	}

	type ResultOrdersBanDetail struct {
		Id         uint      `json:"id"`
		OrderId    string    `json:"order_id"`
		IdBan      int       `json:"id_ban"`
		CodeBan    string    `json:"code_ban"`
		PriceTotal int       `json:"price_total"`
		Category   string    `json:"category"`
		CreatedAt  time.Time `json:"created_at"`
		UpdatedAt  time.Time `json:"updated_at"`
	}

	var res_order_ban []ResultOrdersBanDetail

	database.DB.Table("orders_ban_details obd").Select("obd.id, obd.order_id, obd.id_ban,obd.code_ban,obd.price_total,obd.created_at,obd.updated_at,bc.category as category, CONCAT(category, '-', obd.code_ban) as code_ban").Joins("left join bans on bans.id = obd.id_ban").Joins("left join ban_categories bc on bc.id = bans.ban_category_id").Where("obd.order_id = ?", order_id).Scan(&res_order_ban)

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

}

func GetOrderBanById(c *fiber.Ctx) error {

	// order_ban := models.OrdersBan{
	// 	OrderId: c.Params("id"),
	// }

	// var order_ban_details []models.OrdersBanDetail

	// // result_order_ban := database.DB.Scan(&order_ban)
	// // if result_order_ban.RowsAffected == 0 {
	// // 	return c.SendStatus(404)
	// // }

	order_ban := models.OrdersBan{}

	result_order_ban := database.DB.Table("orders_bans").Where("order_id =?", c.Params("id")).Scan(&order_ban)
	if result_order_ban.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	type ResultOrdersBanDetail struct {
		Id            uint      `json:"id"`
		OrderId       string    `json:"order_id"`
		IdBan         int       `json:"id_ban"`
		CodeBan       string    `json:"code_ban"`
		CodeBanTicket string    `json:"code_ban_ticket"`
		PriceTotal    int       `json:"price_total"`
		Category      string    `json:"category"`
		CreatedAt     time.Time `json:"created_at"`
		UpdatedAt     time.Time `json:"updated_at"`
	}

	var results []ResultOrdersBanDetail

	// database.DB.Table("orders_ban_details").Select("id, order_id, id_ban,code_ban,price_total,created_at,updated_at,ban_categories.category as category").Joins("left join bans on bans.id = id_ban").Joins("left join ban_categories on ban_categories.id = bans.ban_category_id").Where("order_id = ?", c.Params("id")).Scan(&results)

	database.DB.Table("orders_ban_details obd").Select("obd.id, obd.order_id, obd.id_ban,obd.code_ban,obd.price_total,obd.created_at,obd.updated_at,bc.category as category, CONCAT(category, '-', obd.code_ban) as code_ban_ticket").Joins("left join bans on bans.id = obd.id_ban").Joins("left join ban_categories bc on bc.id = bans.ban_category_id").Where("obd.order_id = ?", c.Params("id")).Scan(&results)
	fmt.Print(results)

	// result_order_ban_details := database.DB.Where("order_id = ?", c.Params("id")).Find(&order_ban_details)
	// if result_order_ban_details.RowsAffected == 0 {
	// 	return c.SendStatus(404)
	// }
	return c.Status(200).JSON(fiber.Map{
		"message": "success",
		"data":    order_ban,
		"detail":  results,
	})
}

func OrderBanAjaxList(c *fiber.Ctx) error {

	filterAjax := new(FilterAjaxOrderBan)

	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
	}

	order_ban := models.OrdersBanDetail{
		CodeBan: filterAjax.CodeBan,
	}

	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

	var start, end string

	if filterAjax.StartDate != "" && filterAjax.EndDate != "" {
		start = filterAjax.StartDate + " 00:00:00"
		end = filterAjax.EndDate + " 23:59:59"
	}

	fmt.Println(start)
	fmt.Println(end)

	data, total, err := OrderBanQueryAjaxList(order_ban, limit, offset, sort, start, end)
	fmt.Println(data)

	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 dataResponseOrderBan []models.OrdersBanDetail

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

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

	type MetaInfo struct {
		TotalIncome int64 `json:"total_income"`
		TotalTrx    int64 `json:"total_trx"`
	}

	var results MetaInfo

	database.DB.Table("orders_ban_details").Select("sum(cast(price_total as int)) as total_income, count(*) as total_trx").Where(order_ban).Where("created_at between ? and ?", start, end).Scan(&results)
	fmt.Print(results)

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

func OrderBanAjaxListParent(c *fiber.Ctx) error {

	filterAjax := new(FilterAjaxOrderBan)

	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
	}

	order_ban := models.OrdersBan{}

	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

	var start, end string

	if filterAjax.StartDate != "" && filterAjax.EndDate != "" {
		start = filterAjax.StartDate + " 00:00:00"
		end = filterAjax.EndDate + " 23:59:59"
	}

	fmt.Println(start)
	fmt.Println(end)

	data, total, err := OrderBanQueryAjaxListParent(order_ban, limit, offset, sort, start, end)
	fmt.Println(data)

	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 dataResponseOrderBan []models.OrdersBan

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

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

	type MetaInfo struct {
		TotalIncome int64 `json:"total_income"`
		TotalTrx    int64 `json:"total_trx"`
	}

	var results MetaInfo

	database.DB.Table("orders_bans").Select("sum(cast(price_total as int)) as total_income, count(*) as total_trx").Where(order_ban).Where("created_at between ? and ?", start, end).Scan(&results)
	fmt.Print(results)

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

func OrderBanAjaxListCashierDaily(c *fiber.Ctx) error {

	filterAjax := new(FilterAjaxOrderBan)

	var start, end string

	t := time.Now()
	curr_time := strftime.Format(t, "%Y-%m-%d")
	start = curr_time + " 00:00:00"
	end = curr_time + " 23:59:59"

	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 = 9999
	}

	order_ban := models.OrdersBan{}

	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 := OrderBanQueryAjaxListCashierDaily(order_ban, limit, offset, sort, start, end)
	fmt.Println(data)

	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 dataResponseOrderBan []models.OrdersBan

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

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

	type MetaInfo struct {
		TotalIncome int64 `json:"total_income"`
		TotalTrx    int64 `json:"total_trx"`
	}

	var results MetaInfo

	database.DB.Table("orders_bans").Select("sum(price_total) as total_income, count(*) as total_trx").Where(order_ban).Where("created_at between ? and ?", start, end).Scan(&results)
	fmt.Print(results)

	fmt.Print(results)

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

func OrderBanQueryAjaxList(filter models.OrdersBanDetail, limit, offset int, sort map[string]string, start string, end string) ([]models.OrdersBanDetail, *int64, error) {
	var (
		result         []models.OrdersBanDetail
		count          int64
		query, dbCount *gorm.DB
	)

	if start == "" {
		query = database.DB.Where(filter)
	} else {
		query = database.DB.Where(filter).Where("created_at BETWEEN ? AND ?", start, end)
	}

	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
	}
	if start == "" {
		dbCount = database.DB.Table("orders_ban_details").Where(filter).Select("id").Count(&count)
	} else {
		dbCount = database.DB.Table("orders_ban_details").Where(filter).Where("created_at BETWEEN ? AND ?", start, end).Select("id").Count(&count)
	}

	if dbCount.Error != nil {
		return nil, nil, dbCount.Error
	}
	return result, &count, nil

}

func OrderBanQueryAjaxListParent(filter models.OrdersBan, limit, offset int, sort map[string]string, start string, end string) ([]models.OrdersBan, *int64, error) {
	var (
		result         []models.OrdersBan
		count          int64
		query, dbCount *gorm.DB
	)

	if start == "" {
		query = database.DB.Where(filter)
	} else {
		query = database.DB.Where(filter).Where("created_at BETWEEN ? AND ?", start, end)
	}

	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
	}
	if start == "" {
		dbCount = database.DB.Table("orders_bans").Where(filter).Select("id").Count(&count)
	} else {
		dbCount = database.DB.Table("orders_bans").Where(filter).Where("created_at BETWEEN ? AND ?", start, end).Select("id").Count(&count)
	}

	if dbCount.Error != nil {
		return nil, nil, dbCount.Error
	}
	return result, &count, nil

}

func OrderBanQueryAjaxListCashierDaily(filter models.OrdersBan, limit, offset int, sort map[string]string, start string, end string) ([]models.OrdersBan, *int64, error) {
	var (
		result         []models.OrdersBan
		count          int64
		query, dbCount *gorm.DB
	)

	if start == "" {
		query = database.DB.Where(filter)
	} else {
		query = database.DB.Where(filter).Where("created_at BETWEEN ? AND ?", start, end)
	}

	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).Order("created_at desc").Find(&result)
	fmt.Println(query)
	if query.Error != nil {
		return nil, nil, query.Error
	}
	if start == "" {
		dbCount = database.DB.Table("orders_bans").Where(filter).Select("id").Count(&count)
	} else {
		dbCount = database.DB.Table("orders_bans").Where(filter).Where("created_at BETWEEN ? AND ?", start, end).Select("id").Count(&count)
	}

	if dbCount.Error != nil {
		return nil, nil, dbCount.Error
	}
	return result, &count, nil

}

func DeleteOrderBan(c *fiber.Ctx) error {

	Id := c.Params("id")
	if Id == "" {
		return c.JSON(fiber.Map{
			"message": "id must be set",
		})
	}

	orders := models.OrdersBan{}

	result := database.DB.Where("order_id = ?", Id).Delete(&orders)

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

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

func OrderBanDaily(c *fiber.Ctx) error {
	// var order models.Orders
	// var res_daily_order []models.DailyOrder
	t := time.Now()
	curr_time := strftime.Format(t, "%Y-%m-%d")
	start_time := curr_time + " 00:00:00"
	end_time := curr_time + " 23:59:59"
	fmt.Println(start_time, end_time)

	// Select `id`, `name` automatically when querying
	// .Where("category IN ?", [][]interface{}{{"UMUM", "SEKOLAH"}})
	// order_daily := database.DB.Model(&order).Where("trxdate between ? and ?", start_time, end_time).Group("ticket_name").Find(&res_daily_order)

	type Result struct {
		CodeBan    string `json:"code_ban"`
		Total      int64  `json:"total"`
		PriceTotal string `json:"price"`
		Category   string `json:"category"`
	}

	var results []Result

	database.DB.Table("orders_ban_details").Select("code_ban, price_total, ban_categories.category as category, count(*) as total").Joins("left join bans on bans.id = id_ban").Joins("left join ban_categories on ban_categories.id = bans.ban_category_id").Where("orders_ban_details.created_at between ? and ?", start_time, end_time).Group("category").Scan(&results)
	fmt.Print(results)

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

func ExportOrderBan(c *fiber.Ctx) error {
	filter := new(FilterDateRangeOrderBan)

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

	type MetaInfo struct {
		TotalBan    int64 `json:"total_ban"`
		TotalIncome int64 `json:"total_income"`
		TotalTrx    int64 `json:"total_trx"`
	}

	var info = new(MetaInfo)

	order := models.OrdersBanDetail{
		CodeBan: filter.CodeBan,
	}

	start := filter.StartDate + " 00:00:00"
	end := filter.EndDate + " 23:59:59"
	data, totalTrx, totalBan, totalIncome, err := OrderBanQueryExport(order, start, end)
	if err != nil {
		return c.Status(400).JSON(err.Error())
	}

	var parent_order []models.OrdersBan

	database.DB.Table("orders_bans").Where("created_at BETWEEN ? AND ?", start, end).Find(&parent_order)

	info.TotalTrx = totalTrx
	info.TotalBan = totalBan
	info.TotalIncome = totalIncome

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

func OrderBanQueryExport(filter models.OrdersBanDetail, start string, end string) ([]models.OrdersBanDetail, int64, int64, int64, error) {
	var (
		result                                 []models.OrdersBanDetail
		countTrx, countBan, countIncome        int64
		query, totalTrx, totalBan, totalIncome *gorm.DB
	)

	query = database.DB.Where(filter).Where("created_at BETWEEN ? AND ?", start, end)

	query = query.Find(&result)
	if query.Error != nil {
		return nil, 0, 0, 0, query.Error
	}

	totalTrx = database.DB.Table("orders_bans").Where(filter).Where("created_at BETWEEN ? AND ?", start, end).Count(&countTrx)

	if totalTrx.Error != nil {
		return nil, 0, 0, 0, query.Error
	}

	totalBan = database.DB.Table("orders_ban_details").Select("count(*) as total_ban").Where(filter).Where("created_at BETWEEN ? AND ?", start, end).Scan(&countBan)

	if totalBan.Error != nil {
		return nil, 0, 0, 0, query.Error
	}

	totalIncome = database.DB.Table("orders_ban_details").Select("sum(cast(price_total as int)) as total_income").Where(filter).Where("created_at BETWEEN ? AND ?", start, end).Scan(&countIncome)

	if totalIncome.Error != nil {
		return nil, 0, 0, 0, query.Error
	}

	return result, countTrx, countBan, countIncome, nil

}

func PrintPdfOrderBan(c *fiber.Ctx) error {

	// filter := new(FilterDateRange)
	filter := new(FilterAjaxOrderBan)

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

	type MetaInfo struct {
		TotalBan    int64 `json:"total_ban"`
		TotalIncome int64 `json:"total_income"`
		TotalTrx    int64 `json:"total_trx"`
	}

	var info = new(MetaInfo)

	order := models.OrdersBanDetail{
		CodeBan: filter.CodeBan,
	}

	start := filter.StartDate + " 00:00:00"
	end := filter.EndDate + " 23:59:59"
	fmt.Println(start)
	_, totalTrx, totalBan, totalIncome, err := OrderBanQueryExport(order, start, end)
	if err != nil {
		return c.Status(400).JSON(err.Error())
	}

	info.TotalTrx = totalTrx
	info.TotalBan = totalBan
	info.TotalIncome = totalIncome

	fmt.Println("TOTAL INCOME")
	fmt.Print(info.TotalIncome)

	// data group by ticket name

	type Result struct {
		CodeBan    string `json:"code_ban"`
		PriceTotal string `json:"price_total"`
		Total      int64  `json:"total"`
	}

	var results []Result

	database.DB.Table("orders_ban_details").Select("code_ban, price_total, count(*) as total").Where("created_at between ? and ?", start, end).Where(order).Group("code_ban").Group("price_total").Scan(&results)
	// fmt.Print(results)

	// create csv file

	file, err := os.Create("./print/order_ban.csv")
	defer file.Close()
	if err != nil {
		log.Fatalln("failed to open file", err)
	}
	w := csv.NewWriter(file)
	defer w.Flush()

	// define column headers
	headers := []string{
		"Code Ban",
		"Price",
		" Terjual",
	}

	w.Write(headers)

	fmt.Println(headers)

	var data_csv [][]string
	for _, record := range results {
		row := []string{record.CodeBan, record.PriceTotal, strconv.Itoa(int(record.Total))}
		data_csv = append(data_csv, row)
	}

	w.WriteAll(data_csv)

	// // load csv

	if _, err := os.Stat(path_order_ban()); errors.Is(err, os.ErrNotExist) {
		return c.SendStatus(404)
	}

	data_pdf := loadCSV(path_order_ban())

	pdf := gofpdf.New("P", "mm", "A4", "")

	pdf.AddPage()

	pdf.SetFont("Helvetica", "", 12)
	pdf.WriteAligned(0, 38, fmt.Sprintf("Dari Tanggal : %s", filter.StartDate), "R")
	pdf.Ln(5)
	pdf.WriteAligned(0, 38, fmt.Sprintf("Sampai Tanggal : %s", filter.EndDate), "R")
	pdf.SetFont("Arial", "B", 24)
	pdf.WriteAligned(0, 35, "Zatobay Report", "C")

	pdf = image(pdf)
	ac := accounting.Accounting{Symbol: "Rp.", Precision: 2, Thousand: ".", Decimal: ","}

	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 12)

	pdf.WriteAligned(0, 38, fmt.Sprintf("Total Pendapatan : %s", ac.FormatMoney(totalIncome)), "L")
	pdf.Ln(5)
	pdf.WriteAligned(0, 38, fmt.Sprintf("Total Transaksi	: %d", totalTrx), "L")
	pdf.Ln(5)
	pdf.WriteAligned(0, 38, fmt.Sprintf("Total Ban Terjual	: %d", totalBan), "L")
	pdf.Ln(30)

	pdf = header(pdf, data_pdf[0])
	pdf = table(pdf, data_pdf[1:])

	if pdf.Err() {
		log.Fatalf("Failed creating PDF report: %s\n", pdf.Error())
	}

	pdf_path := "./print/order_ban.pdf"

	err_pdf := pdf.OutputFileAndClose(pdf_path)
	if err_pdf != nil {
		log.Println("ERROR", err.Error())
	}

	if _, err := os.Stat(pdf_path); errors.Is(err, os.ErrNotExist) {
		return c.SendStatus(404)
	}

	return c.Download(pdf_path)

}

func path_order_ban() string {
	if len(os.Args) < 2 {
		return "./print/order_ban.csv"
	}
	return os.Args[1]
}

// func loadCSVOrderBan(path string) [][]string {
// 	f, err := os.Open(path)
// 	if err != nil {
// 		log.Fatalf("Cannot open '%s': %s\n", path, err.Error())
// 	}
// 	defer f.Close()
// 	r := csv.NewReader(f)
// 	rows, err := r.ReadAll()
// 	if err != nil {
// 		log.Fatalln("Cannot read CSV data:", err.Error())
// 	}
// 	return rows
// }

// func header(pdf *gofpdf.Fpdf, hdr []string) *gofpdf.Fpdf {
// 	pdf.SetFont("Times", "B", 14)
// 	pdf.SetFillColor(240, 240, 240)
// 	for _, str := range hdr {
// 		// The `CellFormat()` method takes a couple of parameters to format
// 		// the cell. We make use of this to create a visible border around
// 		// the cell, and to enable the background fill.
// 		pdf.CellFormat(45, 7, str, "1", 0, "", true, 0, "")
// 	}

// 	// Passing `-1` to `Ln()` uses the height of the last printed cell as
// 	// the line height.
// 	pdf.Ln(-1)
// 	return pdf
// }

// ## The Table Body

// In the same fashion, we can create the table body.

// func table(pdf *gofpdf.Fpdf, tbl [][]string) *gofpdf.Fpdf {
// 	// Reset font and fill color.
// 	pdf.SetFont("Times", "", 10)
// 	pdf.SetFillColor(255, 255, 255)

// 	// Every column gets aligned according to its contents.
// 	align := []string{"L", "C", "L", "L", "R", "R"}
// 	for _, line := range tbl {
// 		for i, str := range line {
// 			// Again, we need the `CellFormat()` method to create a visible
// 			// border around the cell. We also use the `alignStr` parameter
// 			// here to print the cell content either left-aligned or
// 			// right-aligned.
// 			pdf.CellFormat(45, 7, str, "1", 0, align[i], false, 0, "")
// 		}
// 		pdf.SetFooterFunc(func() {
// 			// Position at 1.5 cm from bottom
// 			pdf.SetY(-15)
// 			// Arial italic 8
// 			pdf.SetFont("Arial", "I", 8)
// 			// Text color in gray
// 			pdf.SetTextColor(128, 128, 128)
// 			// Page number
// 			pdf.CellFormat(0, 10, fmt.Sprintf("Page %d", pdf.PageNo()),
// 				"", 0, "C", false, 0, "")
// 		})
// 		pdf.Ln(-1)
// 	}
// 	return pdf
// }

// // ## The Image

// // Next, let's not forget to impress our boss by adding a fancy image.
// func image(pdf *gofpdf.Fpdf) *gofpdf.Fpdf {
// 	// The `ImageOptions` method takes a file path, x, y, width, and height
// 	// parameters, and an `ImageOptions` struct to specify a couple of options.
// 	pdf.ImageOptions("./img/zatobay-print.jpg", 10, 10, 70, 22, false, gofpdf.ImageOptions{ImageType: "JPG", ReadDpi: true}, 0, "")
// 	return pdf
// }

// ## Saving The Document
//
// Finally, the convenience method `OutputFileAndClose()` lets us save the
// finished document.
func savePDFOrderBan(pdf *gofpdf.Fpdf) error {
	return pdf.OutputFileAndClose("report_order_ban.pdf")
}
