package api

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

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

// 供应商管理
func Supplier(r *GinRouter) {

	// 创建供应商
	r.POST("/supplier/create", CreateSupplier)

	// 获取供应商详情
	r.GET("/supplier/detail/:id", GetSupplier)

	// 获取供应商列表
	r.GET("/supplier/list", GetSuppliers)

	// 更新供应商
	r.POST("/supplier/update", UpdateSupplier)

	// 删除供应商
	r.POST("/supplier/delete/:id", DelSupplier)

	// 获取供应商列表
	r.GET("/plan/supplier/list", GetPlanSuppliers)

	// 供应商获取自己的单据列表
	r.GETJWT("/supplier/bill/list", SupplierBillList)

	// 供应商接单
	r.POSTJWT("/supplier/bill/ack", SupplierBillAck)

	// 单据分配给供应商
	r.GETJWT("/supplier/bill/alloc", SupplierBillAlloc)

}

const (
	PURCHASE_BILL_TYPE = "purchase"
	PRODUCE_BILL_TYPE  = "produce"
	PRODUCT_BILL_TYPE  = "product"
)

type SupplierSmsTempInfo struct {
	Product      string // 产品名+数量
	SerialNumber string
	Phone        string
}

func genSupplierSmsTemp(billId primitive.ObjectID, billType string, apictx *ApiSession) (*SupplierSmsTempInfo, error) {
	productName := ""
	supplierId := primitive.NilObjectID
	serialNumber := ""
	if billType == PURCHASE_BILL_TYPE {
		purchase := &model.PurchaseBill{}
		found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			CollectName: repo.CollectionBillPurchase,
			Query:       repo.Map{"_id": billId},
			Project:     []string{"productName", "supplierId", "serialNumber", "isAck"},
		}, purchase)
		if !found || err != nil {
			return nil, errors.New("未找到该订单")
		}
		// 已经接单不发送提醒
		if *purchase.IsAck {
			return nil, errors.New("该供应商已经接单")
		}
		serialNumber = purchase.SerialNumber
		productName = purchase.ProductName
		supplierId = purchase.SupplierId

	}
	if billType == PRODUCE_BILL_TYPE {
		produce := &model.ProduceBill{}
		found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			CollectName: repo.CollectionBillProduce,
			Query:       repo.Map{"_id": billId},
			Project:     []string{"productName", "supplierId", "serialNumber", "isAck"},
		}, produce)
		if !found || err != nil {
			return nil, errors.New("未找到该订单")
		}
		// 已经接单不发送提醒
		if *produce.IsAck {
			return nil, errors.New("该供应商已经接单")
		}
		serialNumber = produce.SerialNumber
		productName = produce.ProductName
		supplierId = produce.SupplierId
	}
	if billType == PRODUCT_BILL_TYPE {
		product := &model.ProductBill{}
		found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			CollectName: repo.CollectionBillProduct,
			Query:       repo.Map{"_id": billId},
			Project:     []string{"productName", "supplierId", "serialNumber", "isAck"},
		}, product)
		if !found || err != nil {
			return nil, errors.New("未找到该订单")
		}
		// 已经接单不发送提醒
		if *product.IsAck {
			return nil, errors.New("该供应商已经接单")
		}
		serialNumber = product.SerialNumber
		productName = product.ProductName
		supplierId = product.SupplierId
	}
	// 查询供应商信息
	user, err := getUserById(apictx, supplierId)
	if user == nil || err != nil {
		return nil, errors.New("未找到该供应商信息")
	}
	if len(user.Phone) != 11 {
		return nil, errors.New("手机号信息错误")
	}
	return &SupplierSmsTempInfo{
		Product:      fmt.Sprintf("%s。<%s>", productName, "成都永红印务"),
		SerialNumber: serialNumber,
		Phone:        user.Phone,
	}, nil

}

// 把订单分配给供应商
// purchase produce product
// id为订单id
// /supplier/bill/alloc?id=xxx&type=purchase
func SupplierBillAlloc(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// ?验证当前账户是否可发送订单
	userId, _ := primitive.ObjectIDFromHex(apictx.User.Parent)
	user, err1 := getUserById(apictx, userId)
	if err1 != nil {
		return nil, errors.New("用户错误")
	}
	if !isSender(user.Roles) {
		return nil, errors.New("没有发送权限")
	}

	billId, _ := primitive.ObjectIDFromHex(c.Query("id"))
	if billId.IsZero() {
		return nil, errors.New("订单id不正确")
	}
	billType := c.Query("type")
	billTypes := []string{"purchase", "produce", "product"}
	flagType := false
	for _, bt := range billTypes {
		if bt == billType {
			flagType = true
			break
		}
	}
	if !flagType {
		return nil, errors.New("订单类型错误")
	}

	result := &mongo.UpdateResult{}
	var err error
	switch billType {
	case PURCHASE_BILL_TYPE:
		result, err = repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillPurchase, billId.Hex(), &model.PurchaseBill{IsSend: true, SendTime: time.Now()})
	case PRODUCE_BILL_TYPE:
		result, err = repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, billId.Hex(), &model.ProduceBill{IsSend: true, SendTime: time.Now()})
	case PRODUCT_BILL_TYPE:
		result, err = repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduct, billId.Hex(), &model.ProductBill{IsSend: true, SendTime: time.Now()})
	default:
		return result, nil
	}
	if err == nil {
		// 给供应商发送通知短信
		smsInfo, err := genSupplierSmsTemp(billId, billType, apictx)
		fmt.Println(smsInfo)
		if err == nil {
			var wg sync.WaitGroup
			wg.Add(1)
			go SendSmsNotify(smsInfo.Phone, &SupplierSmsReq{smsInfo.Product, smsInfo.SerialNumber}, &wg)
			// err = SendSmsNotify1(smsInfo.Phone, &SupplierSmsReq{smsInfo.Product, smsInfo.SerialNumber})
			wg.Wait()
		}
	}
	return result, err
}

// 供应商-接单
// purchase produce product
// POST /supplier/bill/ack
// {"id":xxxx,"type":"purchase"}
type SupplierBillAckReq struct {
	Type string
	Id   primitive.ObjectID
}

func SupplierBillAck(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	userId, _ := primitive.ObjectIDFromHex(apictx.User.Parent)
	form := SupplierBillAckReq{}
	err := c.ShouldBindJSON(&form)
	if err != nil {
		return nil, errors.New("参数错误")
	}

	billType := form.Type
	id := form.Id
	_id := form.Id.Hex()
	if id.IsZero() {
		return nil, errors.New("id为空")
	}
	if userId.IsZero() {
		return nil, errors.New("非法用户")
	}
	// purchase produce product
	billTypes := []string{"purchase", "produce", "product"}
	flagType := false
	for _, bt := range billTypes {
		if bt == billType {
			flagType = true
			break
		}
	}
	if !flagType {
		return nil, errors.New("订单类型错误")
	}
	isAck := true
	switch billType {
	case "purchase":
		return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillPurchase, _id, &model.PurchaseBill{IsAck: &isAck, AckTime: time.Now()})
	case "produce":
		return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, _id, &model.ProduceBill{IsAck: &isAck, AckTime: time.Now()})
	case "product":
		return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduct, _id, &model.ProductBill{IsAck: &isAck, AckTime: time.Now()})
	default:
		return nil, errors.New("更新类型错误")
	}

}

// 供应商-订单列表
// purchase produce product
// /supplier/bill/list?type=purchase&query={"status":"created"}
func SupplierBillList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	userId, _ := primitive.ObjectIDFromHex(apictx.User.Parent)
	billType := c.Query("type")
	page, size, query := UtilQueryPageSize(c)
	if userId.IsZero() {
		return nil, errors.New("非法用户")
	}
	// purchase produce product
	billTypes := []string{"purchase", "produce", "product"}
	flagType := false
	for _, bt := range billTypes {
		if bt == billType {
			flagType = true
			break
		}
	}
	if !flagType {
		return nil, errors.New("订单类型错误")
	}
	query["supplierId"] = userId
	query["isSend"] = true

	collectName := ""
	switch billType {
	case "purchase":
		collectName = repo.CollectionBillPurchase
	case "produce":
		collectName = repo.CollectionBillProduce
	case "product":
		collectName = repo.CollectionBillProduct
	default:
		return []map[string]interface{}{}, nil
	}
	return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
		CollectName: collectName,
		Page:        page,
		Size:        size,
		Query:       query,
		Sort:        bson.M{"sendTime": -1},
	})
}

// 创建供应商
func CreateSupplier(c *gin.Context, apictx *ApiSession) (interface{}, error) {

	var supplier model.Supplier

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

	if supplier.Name == "" {
		return nil, errors.New("供应商名为空")
	}
	if supplier.Address == "" {
		return nil, errors.New("供应商地址为空")
	}
	if supplier.Phone == "" {
		return nil, errors.New("供应商联系电话为空")
	}

	supplier.CreateTime = time.Now()
	supplier.UpdateTime = time.Now()

	result, err := repo.RepoAddDoc(ctx, repo.CollectionSupplier, &supplier)
	return result, err
}

// 获取供应商信息
func GetSupplier(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	supplierId := c.Param("id")
	id, err := primitive.ObjectIDFromHex(supplierId)
	if err != nil {
		return nil, errors.New("非法id")
	}
	var supplier model.Supplier
	option := &repo.DocSearchOptions{
		CollectName: repo.CollectionSupplier,
		Query:       repo.Map{"_id": id},
	}

	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), option, &supplier)
	if !found || err != nil {
		log.Info(err)
		return nil, errors.New("数据未找到")
	}

	return supplier, nil
}

// 获取供应商列表
func GetSuppliers(c *gin.Context, apictx *ApiSession) (interface{}, error) {

	page, size, query := UtilQueryPageSize(c)
	if _name, ok := query["name"]; ok {
		delete(query, "name")
		query["name"] = bson.M{"$regex": _name.(string)}
	}

	if cate, ok := query["category"]; ok {
		delete(query, "category")
		query["categorys"] = bson.M{"$in": []string{cate.(string)}}
	}

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

// !暂时弃用
func GetPlanSuppliers(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	page, size, query := UtilQueryPageSize(c)

	emtyPage := &repo.PageResult{
		Total: 0,
		Size:  size,
		Page:  page,
		List:  []map[string]interface{}{},
	}
	listOut := []map[string]interface{}{}

	flag := false
	if query["matId"] != nil || query["craftId"] != nil || query["productId"] != nil {
		flag = true
	}

	filtter := repo.Map{}
	if _name, ok := query["name"]; ok {
		filtter["name"] = bson.M{"$regex": _name.(string)}
	}

	if cate, ok := query["category"]; ok {
		filtter["categorys"] = bson.M{"$in": []string{cate.(string)}}
	}

	if !flag {
		option := &repo.PageSearchOptions{
			CollectName: repo.CollectionSupplier,
			// Query:       repo.Map{"categorys": bson.M{"$in": []string{cate.(string)}}},
			Query: filtter,
			Page:  page,
			Size:  size,
			Sort:  bson.M{"createTime": -1},
		}
		return repo.RepoPageSearch(apictx.CreateRepoCtx(), option)

	}

	//category =>根据内容查询 供应对应内容的供应商

	if query["matId"] != nil {
		matId := query["matId"].(string)
		if len(matId) < 1 {
			return nil, fmt.Errorf("matId(string)为空")
		}
		id, _ := primitive.ObjectIDFromHex(matId)
		ok, list := repo.RepoSeachDocsMap(apictx.CreateRepoCtx(), &repo.DocsSearchOptions{
			CollectName: repo.CollectionSupplierMatprice,
			Query:       repo.Map{"productId": id},
			Project:     []string{"supplierId"},
		})
		if !ok {
			return emtyPage, nil
		}

		listOut = list
	}

	if query["craftId"] != nil {
		cratf := &model.Craft{}

		ok, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			Query:       repo.Map{"_id": query["craftId"].(string)},
			CollectName: repo.CollectionCraft,
		}, cratf)

		if !ok {
			return nil, fmt.Errorf("没有对应的工艺信息")
		}

		//查询工艺分类
		pipleLine := []bson.M{
			{
				"$lookup": bson.M{
					"from":         repo.CollectionCraft,
					"localField":   "productId",
					"foreignField": "_id",
					"as":           "craft_docs",
				},
			},
			{
				"$match": bson.M{
					"craft_docs.0.category": cratf.Category,
				},
			},
			{
				"$project": bson.M{
					"craft_docs": 0,
					"createTime": 0,
					"price":      0,
					"productId":  0,
					"updateTime": 0,
				},
			},
		}
		ctx := apictx.CreateRepoCtx()

		colls := ctx.Client.GetCollection(repo.CollectionSupplierCraftprice)

		findoptions := &options.AggregateOptions{}

		cur, err := colls.Aggregate(ctx.Ctx, pipleLine, findoptions)
		if err != nil {
			return nil, err
		}

		defer cur.Close(ctx.Ctx)

		err = cur.All(ctx.Ctx, &listOut)

		if err != nil {
			return nil, err
		}
		if len(listOut) < 1 {
			return emtyPage, nil
		}
		return listOut, nil
		// cratfId := query["craftId"].(string)
		// if len(cratfId) < 1 {
		// 	return nil, fmt.Errorf("cratfId(string)为空")
		// }
		// id, _ := primitive.ObjectIDFromHex(cratfId)
		// ok, list := repo.RepoSeachDocsMap(apictx.CreateRepoCtx(), &repo.DocsSearchOptions{
		// 	CollectName: repo.CollectionSupplierCraftprice,
		// 	Query:       repo.Map{"craftId": id},
		// 	Project:     []string{"supplierId"},
		// })
		// if !ok {
		// 	return emtyPage, nil
		// }

		// listOut = list
	}

	if query["productId"] != nil {
		productId := query["productId"].(string)
		if len(productId) < 1 {
			return nil, fmt.Errorf("productId(string)为空")
		}
		id, _ := primitive.ObjectIDFromHex(productId)
		ok, list := repo.RepoSeachDocsMap(apictx.CreateRepoCtx(), &repo.DocsSearchOptions{
			CollectName: repo.CollectionSupplierProductprice,
			Query:       repo.Map{"productId": id},
			Project:     []string{"supplierId"},
		})
		if !ok {
			return emtyPage, nil
		}

		listOut = list
	}

	//获取供应商列表
	suppliers := []primitive.ObjectID{}
	suppliersMap := map[string]bool{}
	for _, item := range listOut {
		if item["supplierId"] != nil {

			id, ok := item["supplierId"].(primitive.ObjectID)
			if !ok {
				continue
			}
			if !suppliersMap[id.Hex()] {
				suppliers = append(suppliers, id)
				suppliersMap[id.Hex()] = true
			}
		}
	}
	if len(suppliers) < 1 {
		return emtyPage, nil
	}

	filtter["_id"] = bson.M{"$in": suppliers}
	option := &repo.PageSearchOptions{
		CollectName: repo.CollectionSupplier,
		Query:       filtter,
		// Query:       repo.Map{"_id": bson.M{"$in": suppliers}},
		Page: page,
		Size: size,
		Sort: bson.M{"createTime": -1},
	}
	return repo.RepoPageSearch(apictx.CreateRepoCtx(), option)
}

// 更新供应商
func UpdateSupplier(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	var supplier model.Supplier
	err := c.ShouldBindJSON(&supplier)
	if err != nil {
		return nil, errors.New("参数错误")
	}
	if supplier.Id.Hex() == "" {
		return nil, errors.New("id的为空")
	}
	supplier.UpdateTime = time.Now()
	return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionSupplier, supplier.Id.Hex(), &supplier)
}

// 删除供应商
func DelSupplier(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	supplierId := c.Param("id")
	if supplierId == "" {
		return nil, errors.New("id为空")
	}

	return repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionSupplier, supplierId)
}
