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.GETJWT("/bill/product/detail/:id", GetProductBill)

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

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

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

	//下载单据
	r.GETJWT("/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)
	return repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionBillProduct, _id, &product, &repo.RecordLogReq{
		Path:     c.Request.URL.Path,
		UserInfo: user,
		TargetId: _id,
		Type:     "reviewed",
	})

}

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

	result, err := repo.RepoAddDoc1(ctx, repo.CollectionBillProduct, &bill, &repo.RecordLogReq{
		Path:     c.Request.URL.Path,
		UserInfo: userInfo,
		TargetId: "",
		Type:     "created",
	})
	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)

	option := &repo.PageSearchOptions{
		CollectName: repo.CollectionBillProduct,
		Query:       makeBillQuery(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(c, apictx, bill.Type)
			if err != nil {
				return nil, err
			}

		}
	}
	// 计算结算价格
	userId, _ := primitive.ObjectIDFromHex(apictx.User.ID)
	user, _ := getUserById(apictx, userId)
	logType := "update"
	// 更改状态
	ok, err := isCompareStatus(apictx, repo.CollectionBillProduct, bill.Id, bill.Status)
	if err != nil {
		return nil, err
	}
	if bill.Status == "complete" {
		if !ok {
			bill.CompleteTime = time.Now()
			logType = "complete"
		}
	}
	if bill.Status == "deprecated" {
		if !ok {
			logType = "deprecated"
		}

	}

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

	// 修改单据信息需要同步plan中stage项
	if len(bill.Products) > 0 {
		// 获取当前订单供应商id
		// 对比供应商是否变化,变化了就同步计划中的供应商
		currProduct := &model.ProductBill{}
		repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			CollectName: repo.CollectionBillProduct,
			Query:       repo.Map{"_id": bill.Id},
			Project:     []string{"supplierId"},
		}, currProduct)
		var supplierInfo *model.Supplier
		if currProduct.SupplierId != bill.SupplierId {
			// 查询更改后的supplierInfo
			supplierInfo = &model.Supplier{}
			repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
				CollectName: repo.CollectionSupplier,
				Query:       repo.Map{"_id": bill.SupplierId},
			}, supplierInfo)
		}
		idStatges := make(map[string]*UpdateBilltoStageReq)
		for _, product := range bill.Products {
			if len(product.Id) == 0 {
				continue
			}

			idStatges[product.Id] = &UpdateBilltoStageReq{
				BillType:     "product",
				SupplierInfo: supplierInfo,
				Norm:         product.Norm,
				Size:         product.Size,
				OrderCount:   product.OrderCount,
				OrderPrice:   product.OrderPrice,
				ConfirmCount: product.ConfirmCount,
				Remark:       product.Remark,
				DeliveryTime: product.DeliveryTime,
			}
		}
		_, err := updateBilltoStage(c, bill.PlanId, idStatges, apictx)
		if err != nil {
			fmt.Println(err)
			return nil, errors.New("该单据改动同步到产品失败")
		}
		fmt.Println("单据同步到产品,planId:", bill.PlanId)
	}

	bill.UpdateTime = time.Now()
	// return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduct, bill.Id.Hex(), &bill)
	return repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionBillProduct, bill.Id.Hex(), &bill, &repo.RecordLogReq{
		Path:     c.Request.URL.Path,
		UserInfo: user,
		TargetId: bill.Id.Hex(),
		Type:     logType,
	})

}

// 删除单据
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
}