package api

import (
	"box-cost/db/model"
	"box-cost/db/repo"
	"box-cost/log"
	"errors"
	"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 Summary(r *GinRouter) {

	// 下载详细汇总
	r.GETJWT("/summary/download", SummaryDownload)
	// 下载简单汇总
	r.GETJWT("/summary/sample/download", SummarySampleDownload)

	// !10.27 时间和供应商查询
	// summary/supplier/plan query={"supplierId":"xxx","timeRange":["xxx","xxx"]}
	// 返回planIds数组 []string
	r.GETJWT("/summary/supplier/plan", SummarySupplierPlan)
}

type SupplierPlanSummary struct {
	Plans      []*PlanSummary
	SupplierId primitive.ObjectID
	ApiSession *ApiSession
}
type PlanSummary struct {
	Plan         *model.ProductPlan
	IsSend       map[string]bool
	IsAck        map[string]bool
	Reviewed     map[string]int32
	State        map[string]string
	CreateTimes  map[string]time.Time
	SerialNumber map[string]string
	SendTo       map[string]string
}

type PlanSimple struct {
	Id         primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
	Name       string             `bson:"name,omitempty" json:"name"`
	CreateUser string             `bson:"createUser,omitempty" json:"createUser"`
	//生产数量
	Total int `bson:"total,omitempty" json:"total"`
	//状态
	Status string `bson:"status,omitempty" json:"status"`
	//总价
	TotalPrice float64   `bson:"totalPrice,omitempty" json:"totalPrice"`
	CreateTime time.Time `bson:"createTime,omitempty" json:"createTime"`
}

func SummarySupplierPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	_, _, query := UtilQueryPageSize(c)
	supplierId := primitive.NilObjectID
	if _supplierId, ok := query["supplierId"]; ok {
		supplierId, _ = primitive.ObjectIDFromHex(_supplierId.(string))
		delete(query, "supplierId")
	}
	if _timeRange, ok := query["timeRange"]; ok {
		timeRange, _ := _timeRange.([]interface{})

		if len(timeRange) == 2 {
			start, end := getTimeRange(timeRange[0].(string), timeRange[1].(string))
			query["createTime"] = bson.M{"$gte": start, "$lte": end}
		}
		delete(query, "timeRange")
	}
	// 遍历判断包含供应商的数据,返回planIds
	plans := []*model.ProductPlan{}
	err := repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
		CollectName: repo.CollectionProductPlan,
		Query:       query,
		Sort:        bson.M{"createTime": -1},
	}, &plans)
	if err != nil {
		log.Error(err)
		return nil, errors.New("查询数据错误!")
	}
	planSimples := []*PlanSimple{}
	if len(plans) < 1 {
		return planSimples, nil
	}
	// 遍历

	for _, plan := range plans {
		flag := false
		// !20240425兼容totalPrice为空的情况
		var totalPrice float64 = 0
		if plan.TotalPrice != nil {
			totalPrice = *plan.TotalPrice
		}
		ps := &PlanSimple{
			Id:         plan.Id,
			Name:       plan.Name,
			CreateUser: plan.CreateUser,
			Total:      plan.Total,
			Status:     plan.Status,
			TotalPrice: totalPrice,
			CreateTime: plan.CreateTime,
		}
		// 选供应商
		if !supplierId.IsZero() {
			for _, comp := range plan.Pack.Components {
				if comp.Id == "" || len(comp.Stages) == 0 {
					continue
				}
				for _, stage := range comp.Stages {
					// 只要任意一个stage中存在选中的供应商,那么这个计划包含这个供应商,这时应该跳出来
					if stage.SupplierInfo == nil {
						continue
					}
					if stage.SupplierInfo.Id == supplierId {
						planSimples = append(planSimples, ps)
						flag = true
						break
					}
				}
				if flag {
					break
				}
			}

		} else {
			planSimples = append(planSimples, ps)
		}
	}

	return planSimples, nil
}

// /summary/download?planIds=id1,id2&supplierId=xxx
func SummaryDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 获取planIds supplierId
	_planIds := c.Query("planIds")       // id1,id2...
	_supplierId := c.Query("supplierId") // 供应商id
	planIds := strings.Split(_planIds, ",")
	supplierId, _ := primitive.ObjectIDFromHex(_supplierId)

	// 获取详情
	if len(planIds) < 1 {
		return nil, errors.New("数据不存在")
	}
	summaryPlans := []*PlanSummary{}
	for _, _planId := range planIds {
		id, _ := primitive.ObjectIDFromHex(_planId)
		if id.IsZero() {
			return nil, errors.New("非法id")
		}
		plan := &model.ProductPlan{}

		found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			CollectName: repo.CollectionProductPlan,
			Query:       repo.Map{"_id": id},
		}, plan)
		if !found || err != nil {
			continue
		}

		summaryPlan := GetPlanStatus(plan, apictx)
		summaryPlans = append(summaryPlans, summaryPlan)

	}
	if len(summaryPlans) < 1 {
		return nil, errors.New("数据不存在")
	}

	// 实例化表格,传入数据
	f := excelize.NewFile()
	index := f.NewSheet("Sheet1")
	f.SetActiveSheet(index)
	f.SetDefaultFont("宋体")
	planSummaryExcel := NewPlanSummaryExcel(f)
	planSummaryExcel.Content = &SupplierPlanSummary{
		Plans:      summaryPlans,
		SupplierId: supplierId,
		ApiSession: apictx,
	}
	// 绘制表格
	planSummaryExcel.Draws()
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename="+"planSummary.xlsx")
	c.Header("Content-Transfer-Encoding", "binary")

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

	return nil, nil
}

// /summary/sample/download?planIds=id1,id2&supplierId=xxx
func SummarySampleDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 获取planIds supplierId
	_planIds := c.Query("planIds")       // id1,id2...
	_supplierId := c.Query("supplierId") // 供应商id
	planIds := strings.Split(_planIds, ",")

	supplierId, _ := primitive.ObjectIDFromHex(_supplierId)

	// 获取详情
	if len(planIds) < 1 {
		return nil, errors.New("数据不存在")
	}
	summaryPlans := []*PlanSummary{}
	for _, _planId := range planIds {
		id, _ := primitive.ObjectIDFromHex(_planId)
		if id.IsZero() {
			return nil, errors.New("非法id")
		}
		plan := &model.ProductPlan{}

		found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
			CollectName: repo.CollectionProductPlan,
			Query:       repo.Map{"_id": id},
		}, plan)
		if !found || err != nil {
			continue
		}

		summaryPlan := GetPlanStatus(plan, apictx)
		summaryPlans = append(summaryPlans, summaryPlan)

	}
	if len(summaryPlans) < 1 {
		return nil, errors.New("数据不存在")
	}

	// 实例化表格,传入数据
	f := excelize.NewFile()
	index := f.NewSheet("Sheet1")
	f.SetActiveSheet(index)
	f.SetDefaultFont("宋体")
	planSummaryExcel := NewSummarySampleExcel(f)
	planSummaryExcel.Content = &SupplierPlanSummary{
		Plans:      summaryPlans,
		SupplierId: supplierId,
	}
	// 绘制表格
	planSummaryExcel.Draws()
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename="+"planSummary.xlsx")
	c.Header("Content-Transfer-Encoding", "binary")

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

	return nil, nil

}

func GetPlanStatus(plan *model.ProductPlan, apictx *ApiSession) *PlanSummary {
	billStates := map[string]string{}
	billSerialNumber := map[string]string{}
	billSendTo := map[string]string{}
	billIsSend := map[string]bool{}
	billReviewed := map[string]int32{}
	billIsAck := map[string]bool{}
	billCreateTimes := map[string]time.Time{}
	if plan.Pack != nil && plan.Pack.Components != nil {
		for _, comp := range plan.Pack.Components {
			if comp.Stages != nil {
				for _, stage := range comp.Stages {

					if len(stage.BillId) > 0 {
						collectName := ""
						// 材料
						if stage.BillType == 1 {
							collectName = repo.CollectionBillPurchase
						}
						// 工艺
						if stage.BillType == 2 {
							collectName = repo.CollectionBillProduce
						}
						// 成品
						if stage.BillType == 3 {
							collectName = repo.CollectionBillProduct
						}

						ok, state := repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
							CollectName: collectName,
							Query:       repo.Map{"_id": stage.BillId},
							Project:     []string{"status", "isSend", "reviewed", "isAck", "serialNumber", "sendTo", "remark", "createTime"}})
						if ok {
							billStates[stage.BillId] = state["status"].(string)
							billSerialNumber[stage.BillId] = state["serialNumber"].(string)
							if v, ok := state["sendTo"]; ok {
								billSendTo[stage.BillId] = v.(string)
							}
							if v, ok := state["isSend"]; ok {
								billIsSend[stage.BillId] = v.(bool)

							} else {
								billIsSend[stage.BillId] = false
							}
							if v, ok := state["reviewed"]; ok {
								billReviewed[stage.BillId] = v.(int32)
							} else {
								billReviewed[stage.BillId] = -1
							}
							if v, ok := state["isAck"]; ok {
								billIsAck[stage.BillId] = v.(bool)

							} else {
								billIsAck[stage.BillId] = false
							}
							if v, ok := state["createTime"]; ok {
								billCreateTimes[stage.BillId] = v.(primitive.DateTime).Time()

							}

						}
					}

				}
			}
		}
	}
	return &PlanSummary{
		Plan:         plan,
		IsSend:       billIsSend,
		IsAck:        billIsAck,
		Reviewed:     billReviewed,
		State:        billStates,
		CreateTimes:  billCreateTimes,
		SerialNumber: billSerialNumber,
		SendTo:       billSendTo,
	}
}