package api

import (
	"box-cost/db/model"
	"box-cost/db/repo"
	"context"

	"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"
)

// StageRequest 用于添加和更新stage的请求结构
type StageRequest struct {
	PlanId  string                `json:"planId"`
	PackId  string                `json:"packId"`
	CompId  string                `json:"compId"`
	StageId string                `json:"stageId,omitempty"`
	Stage   *model.ComponentStage `json:"stage"`
}

// 更新计划和部件的价格
func updatePrices(ctx context.Context, db *mongo.Collection, planId primitive.ObjectID, compId string) error {
	// 1. 获取计划详情
	var plan model.ProductPlan
	err := db.FindOne(ctx, bson.M{"_id": planId}).Decode(&plan)
	if err != nil {
		return err
	}

	// 2. 遍历所有组件,找到目标组件并重新计算价格
	var totalPrice float64 = 0
	for _, comp := range plan.Pack.Components {
		compPrice := 0.0
		// 计算组件的所有stage总价
		for _, stage := range comp.Stages {
			stagePrice := stage.OrderPrice * float64(stage.OrderCount)
			compPrice += stagePrice
		}
		// 更新组件总价
		if comp.Id == compId {
			_, err = db.UpdateOne(ctx,
				bson.M{"_id": planId, "pack.components.id": compId},
				bson.M{"$set": bson.M{"pack.components.$.totalPrice": compPrice}})
			if err != nil {
				return err
			}
		}
		totalPrice += compPrice
	}

	// 3. 更新计划总价
	_, err = db.UpdateOne(ctx,
		bson.M{"_id": planId},
		bson.M{"$set": bson.M{"totalPrice": &totalPrice}})
	return err
}

// 增加stage
// 根据planId packId compentId定位到到计划中的compent
// 注意更新计划价格 组件价格
func AddStage(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	var req StageRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		return nil, err
	}

	planId, err := primitive.ObjectIDFromHex(req.PlanId)
	if err != nil {
		return nil, err
	}

	// 创建新的stage,使用请求中的stage数据
	newStage := req.Stage
	newStage.Id = primitive.NewObjectID().Hex() // 确保生成新的ID

	// 更新数据库
	db := apictx.Svc.Mongo.GetCollection(repo.CollectionProductPlan)
	update := bson.M{
		"$push": bson.M{
			"pack.components.$[components].stages": newStage,
		},
	}
	arrayFilters := []interface{}{
		bson.M{"components.id": req.CompId},
	}

	opts := options.Update().SetArrayFilters(options.ArrayFilters{
		Filters: arrayFilters,
	})

	result, err := db.UpdateOne(apictx.CreateRepoCtx().Ctx,
		bson.M{"_id": planId},
		update,
		opts,
	)

	if err != nil {
		return nil, err
	}

	// 更新价格
	err = updatePrices(apictx.CreateRepoCtx().Ctx, db, planId, req.CompId)
	if err != nil {
		return nil, err
	}

	return result, nil
}

// 删除stage
// 根据planId packId compentId stageId定位到到计划中的stage
// 注意更新计划价格 组件价格
func DeleteStage(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	var req StageRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		return nil, err
	}

	planId, err := primitive.ObjectIDFromHex(req.PlanId)
	if err != nil {
		return nil, err
	}

	// 更新数据库
	db := apictx.Svc.Mongo.GetCollection(repo.CollectionProductPlan)
	update := bson.M{
		"$pull": bson.M{
			"pack.components.$[components].stages": bson.M{
				"id": req.StageId,
			},
		},
	}
	arrayFilters := []interface{}{
		bson.M{"components.id": req.CompId},
	}

	opts := options.Update().SetArrayFilters(options.ArrayFilters{
		Filters: arrayFilters,
	})

	result, err := db.UpdateOne(apictx.CreateRepoCtx().Ctx,
		bson.M{"_id": planId},
		update,
		opts,
	)

	if err != nil {
		return nil, err
	}

	// 更新价格
	err = updatePrices(apictx.CreateRepoCtx().Ctx, db, planId, req.CompId)
	if err != nil {
		return nil, err
	}

	return result, nil
}

// 更新stage
// 根据planId packId compentId stageId定位到到计划中的stage
// 注意更新计划价格 组件价格
func UpdateStage(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	var req StageRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		return nil, err
	}

	planId, err := primitive.ObjectIDFromHex(req.PlanId)
	if err != nil {
		return nil, err
	}

	// 更新数据库
	db := apictx.Svc.Mongo.GetCollection(repo.CollectionProductPlan)
	update := bson.M{
		"$set": bson.M{
			"pack.components.$[components].stages.$[stage]": req.Stage,
		},
	}

	arrayFilters := []interface{}{
		bson.M{"components.id": req.CompId},
		bson.M{"stage.id": req.StageId},
	}

	opts := options.Update().SetArrayFilters(options.ArrayFilters{
		Filters: arrayFilters,
	})

	result, err := db.UpdateOne(apictx.CreateRepoCtx().Ctx,
		bson.M{"_id": planId},
		update,
		opts,
	)

	if err != nil {
		return nil, err
	}

	// 更新价格
	err = updatePrices(apictx.CreateRepoCtx().Ctx, db, planId, req.CompId)
	if err != nil {
		return nil, err
	}

	return result, nil
}