package api

import (
	"box-cost/db/model"
	"box-cost/db/repo"
	"box-cost/log"
	"errors"
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

// 单据管理
func BillProduce(r *GinRouter) {

	// 创建单据
	r.POST("/bill/produce/create", CreateProduceBill)

	// 获取单据详情
	r.GET("/bill/produce/detail/:id", GetProduceBill)

	// 获取单据列表
	r.GET("/bill/produce/list", GetProduceBills)

	// 更新单据
	r.POST("/bill/produce/update", UpdateProduceBill)

	// 删除单据
	r.POST("/bill/produce/delete/:id", DelProduceBill)

	//下载单据
	r.GET("/bill/produce/download", DownProduceBill)

	// 审核单据
	r.POSTJWT("/bill/produce/review/:id", ProduceReview)
}

// 审核单据
func ProduceReview(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	_id := c.Param("id")
	id, err := primitive.ObjectIDFromHex(_id)
	if err != nil {
		return nil, errors.New("id错误")
	}
	userId, err := primitive.ObjectIDFromHex(apictx.User.Parent)
	if err != nil {
		return nil, errors.New("用户异常")
	}
	user, err := getUserById(apictx, userId)
	if err != nil {
		return nil, errors.New("查找用户失败")
	}
	if !isManager(user.Roles) {
		return nil, errors.New("该用户没有权限")
	}
	// 查询单据获取已有的签字
	bill := model.ProduceBill{}
	repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: repo.CollectionBillProduce,
		Query:       repo.Map{"_id": id, "reviewed": 1},
	}, &bill)
	signs := make([]primitive.ObjectID, 0)
	if len(bill.SignUsers) > 0 {
		// 如果自己已存在该集合中了
		for _, signUser := range bill.SignUsers {
			if signUser == userId {
				return nil, errors.New("该单据您已审核过了")
			}
		}
		signs = bill.SignUsers
	}

	// 更改状态为已审核 并签字
	signs = append(signs, userId)
	produce := model.ProduceBill{
		Reviewed:   1,
		UpdateTime: time.Now(),
		SignUsers:  signs,
	}
	return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, _id, &produce)

}

// 创建生产加工单据
func CreateProduceBill(c *gin.Context, apictx *ApiSession) (interface{}, error) {

	bill := &model.ProduceBill{}
	err := c.ShouldBindJSON(bill)
	if err != nil {
		fmt.Println(err)
		return nil, errors.New("参数错误!")
	}
	ctx := apictx.CreateRepoCtx()

	if bill.PackId.Hex() == "" {
		return nil, errors.New("包装产品id为空")
	}
	if bill.PlanId.Hex() == "" {
		return nil, errors.New("生产计划id为空")
	}
	if bill.Type == "" {
		return nil, errors.New("类型为空")
	}

	bill.SerialNumber, err = generateSerial(apictx, bill.Type)
	if err != nil {
		return nil, err
	}

	bill.Status = "created"
	if bill.Reviewed == 0 {
		bill.Reviewed = -1
	}
	bill.CreateTime = time.Now()
	bill.UpdateTime = time.Now()

	result, err := repo.RepoAddDoc(ctx, repo.CollectionBillProduce, &bill)
	return result, err
}

// 获取单据信息
func GetProduceBill(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	billId := c.Param("id")
	id, err := primitive.ObjectIDFromHex(billId)
	if err != nil {
		return nil, errors.New("非法id")
	}
	var bill model.ProduceBill
	option := &repo.DocSearchOptions{
		CollectName: repo.CollectionBillProduce,
		Query:       repo.Map{"_id": id},
	}
	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), option, &bill)
	if !found || err != nil {
		log.Info(err)
		return nil, errors.New("数据未找到")
	}

	return bill, nil
}

// 获取单据列表
func GetProduceBills(c *gin.Context, apictx *ApiSession) (interface{}, error) {

	page, size, query := UtilQueryPageSize(c)

	if query["packId"] != nil {
		query["packId"], _ = primitive.ObjectIDFromHex(query["packId"].(string))
	}
	if query["planId"] != nil {
		query["planId"], _ = primitive.ObjectIDFromHex(query["planId"].(string))
	}

	// 时间范围查询
	// createTime 选中的当天时间
	st, ok1 := query["startTime"]
	delete(query, "startTime")
	et, ok2 := query["endTime"]
	delete(query, "endTime")
	if ok1 && ok2 {
		startTime := st.(time.Time)
		endTime := et.(time.Time)
		start, end := getTimeRange(startTime, endTime)
		query["createTime"] = bson.M{"$gte": start, "$lte": end}
	}

	option := &repo.PageSearchOptions{
		CollectName: repo.CollectionBillProduce,
		Query:       query,
		Page:        page,
		Size:        size,
		Sort:        bson.M{"createTime": -1},
	}
	return repo.RepoPageSearch(apictx.CreateRepoCtx(), option)
}

// 更新单据
func UpdateProduceBill(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	var bill model.ProduceBill
	err := c.ShouldBindJSON(&bill)
	if err != nil {
		return nil, errors.New("参数错误")
	}
	if bill.Id.Hex() == "" {
		return nil, errors.New("id的为空")
	}

	billType, err := searchBillTypeById(apictx, repo.CollectionBillProduce, bill.Id)
	if err != nil {
		return nil, err
	}

	// 如果更改类型
	if billType != bill.Type {
		bill.SerialNumber, err = generateSerial(apictx, bill.Type)
		if err != nil {
			return nil, err
		}

	}

	bill.UpdateTime = time.Now()
	return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, bill.Id.Hex(), &bill)
}

// 删除单据
func DelProduceBill(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	billId := c.Param("id")
	if billId == "" {
		return nil, errors.New("id为空")
	}

	return repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, billId)
}

func DownProduceBill(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	billId := c.Query("id")
	isPdf := c.Query("isPdf")
	if len(billId) < 1 {
		return nil, fmt.Errorf("id不能为空")
	}

	id, err := primitive.ObjectIDFromHex(billId)
	if err != nil {
		return nil, errors.New("非法id")
	}
	var bill model.ProduceBill
	option := &repo.DocSearchOptions{
		CollectName: repo.CollectionBillProduce,
		Query:       repo.Map{"_id": id},
	}
	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), option, &bill)
	if !found || err != nil {
		log.Info(err)
		return nil, errors.New("数据未找到")
	}

	f := excelize.NewFile()
	// Create a new sheet.
	index := f.NewSheet("Sheet1")
	f.SetActiveSheet(index)
	f.SetDefaultFont("宋体")

	billExcel := NewProduceBill(f)
	// 获取已审核的签名数据
	if bill.Reviewed == 1 {
		if len(bill.SignUsers) > 0 {
			signs := []*model.Signature{}
			repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
				CollectName: repo.CollectionSignature,
				Query:       repo.Map{"userId": bson.M{"$in": bill.SignUsers}},
				Sort:        bson.M{"sort": 1}, // 升序
			}, &signs)
			billExcel.Signatures = signs
		}

	}
	billExcel.Content = &bill
	info := model.Setting{}
	repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: "infos",
	}, &info)
	billExcel.Title = fmt.Sprintf("%s加工单", info.CompanyName)
	//设置对应的数据
	billExcel.Draws()

	// 下载为pdf
	if isPdf == "true" {
		buf, _ := f.WriteToBuffer()
		res, err := excelToPdf(buf, apictx.Svc.Conf.PdfApiAddr)
		if err != nil {
			return nil, errors.New("转化pdf失败")
		}
		c.Header("Content-Type", "application/octet-stream")
		c.Header("Content-Disposition", "attachment; filename="+"bill.pdf")
		c.Header("Content-Transfer-Encoding", "binary")
		err = res.Write(c.Writer)
		if err != nil {
			return nil, err
		}
		return nil, nil
	}

	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename="+"bill.xlsx")
	c.Header("Content-Transfer-Encoding", "binary")

	err = f.Write(c.Writer)
	if err != nil {
		return nil, err
	}

	return nil, nil
}