package api

import (
	"box-cost/db/model"
	"box-cost/db/repo"
	"errors"
	"strings"
	"time"

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

// 汇总
func Summary(r *GinRouter) {

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

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
}

// /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)
							billSendTo[stage.BillId] = state["sendTo"].(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,
	}
}
