package api

import (
	"box-cost/db/model"
	"box-cost/db/repo"
	"box-cost/log"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"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.POSTJWT("/bill/produce/create", CreateProduceBill)

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

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

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

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

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

}

// 创建生产加工单据
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(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()
	notAck := false
	_isSend := false
	bill.IsSend = &_isSend
	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.CollectionBillProduce, &bill, &repo.RecordLogReq{
		Path:     c.Request.URL.Path,
		UserInfo: userInfo,
		TargetId: "",
		Type:     "created",
	})
	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)

	option := &repo.PageSearchOptions{
		CollectName: repo.CollectionBillProduce,
		Query:       makeBillQuery(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 {
		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.CollectionBillProduce, 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.CollectionBillProduce, 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.Produces) > 0 {
		// 获取当前订单供应商id
		// 对比供应商是否变化,变化了就同步计划中的供应商
		currProduce := &model.ProduceBill{}
		repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			CollectName: repo.CollectionBillProduce,
			Query:       repo.Map{"_id": bill.Id},
			Project:     []string{"supplierId"},
		}, currProduce)
		var supplierInfo *model.Supplier
		if currProduce.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 _, produce := range bill.Produces {
			if len(produce.Id) == 0 {
				continue
			}
			ps := strings.Split(produce.PrintSize, "*")
			width := 0
			height := 0
			if len(ps) == 2 {
				height, _ = strconv.Atoi(ps[0])
				width, _ = strconv.Atoi(ps[1])
			}

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

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

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

	}
	// 覆膜、打印与其他有来纸尺寸类型互斥
	// 如果是这两种类型,不管isPaper的值,都需要有自己的表格
	if bill.IsLam || bill.IsPrint {
		bill.IsPaper = false
	}
	billExcel.Content = &bill
	billExcel.IsPdf = isPdf
	companyName := getCompanyName(apictx)
	billExcel.Title = fmt.Sprintf("%s加工单", 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失败")
		}

		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
}