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 BillProduct(r *GinRouter) {

	// 创建单据
	r.POSTJWT("/bill/product/create", CreateProductBill)

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

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

	// 更新单据
	r.POST("/bill/product/update", UpdateProductBill)

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

	//下载单据
	r.GET("/bill/product/download", DownProductBill)

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

// 审核单据
func ProductReview(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.ProductBill{}
	repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: repo.CollectionBillProduct,
		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)
	product := model.ProductBill{
		Reviewed:   1,
		UpdateTime: time.Now(),
		SignUsers:  signs,
	}
	return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduct, _id, &product)

}

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

	bill := &model.ProductBill{}
	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()
	notAck := false
	bill.IsAck = &notAck
	// 制单人数据
	userId, _ := primitive.ObjectIDFromHex(apictx.User.Parent)
	fmt.Println("userId:", apictx.User.Parent)
	if !userId.IsZero() {
		user, err := getUserById(apictx, userId)
		if err == nil {
			bill.UserName = user.Name
			bill.UserId = userId
		}
	}

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

// 获取单据信息
func GetProductBill(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.ProductBill
	option := &repo.DocSearchOptions{
		CollectName: repo.CollectionBillProduct,
		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 GetProductBills(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.(string)
		endTime := et.(string)
		start, end := getTimeRange(startTime, endTime)
		query["createTime"] = bson.M{"$gte": start, "$lte": end}
	}

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

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

	// 如果更改类型
	if len(bill.Type) > 0 {
		billType, err := searchBillTypeById(apictx, repo.CollectionBillProduct, 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
			}

		}
	}
	// 计算结算价格
	if bill.Status == "complete" {
		bill.CompleteTime = time.Now()
	}

	if bill.Remark == "" {
		bill.Remark = " "
	}
	if bill.SupplierRemark == "" {
		bill.SupplierRemark = " "
	}

	// 更新供应商确定数量与plan中stage项的同步
	if len(bill.Products) > 0 {
		idCounts := map[string]int{}
		for _, product := range bill.Products {
			if len(product.Id) == 0 {
				continue
			}
			idCounts[product.Id] = product.ConfirmCount
		}
		fmt.Println(idCounts)
		result, err := updateStageCount(bill.Id, bill.PlanId, idCounts, apictx)
		if err != nil {
			fmt.Println(err)
			log.Error(err)
		}
		fmt.Println(result)
	}

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

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

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

func DownProductBill(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.ProductBill
	option := &repo.DocSearchOptions{
		CollectName: repo.CollectionBillProduct,
		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()
	index := f.NewSheet("Sheet1")
	f.SetActiveSheet(index)
	f.SetDefaultFont("宋体")

	billExcel := NewProductBill(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{"_id": bson.M{"$in": bill.SignUsers}},
				Sort:        bson.M{"sort": 1}, // 升序
			}, &signs)
			billExcel.Signatures = signs
		}

	}
	billExcel.Content = &bill
	billExcel.IsPdf = isPdf
	billExcel.Title = getCompanyName(apictx)
	//设置对应的数据
	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失败")
		}
		defer res.Body.Close()
		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
}
