package admin_product

import (
	"context"
	"sync"
	"tydata-server/app/main/api/internal/svc"
	"tydata-server/app/main/api/internal/types"
	"tydata-server/app/main/model"
	"tydata-server/common/xerr"

	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/mr"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

type AdminUpdateProductFeaturesLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewAdminUpdateProductFeaturesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateProductFeaturesLogic {
	return &AdminUpdateProductFeaturesLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *AdminUpdateProductFeaturesLogic) AdminUpdateProductFeatures(req *types.AdminUpdateProductFeaturesReq) (resp *types.AdminUpdateProductFeaturesResp, err error) {
	// 1. 查询现有关联
	builder := l.svcCtx.ProductFeatureModel.SelectBuilder().
		Where("product_id = ?", req.ProductId)
	existingList, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "id ASC")
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
			"查询现有产品功能关联失败, err: %v, product_id: %d", err, req.ProductId)
	}

	// 2. 构建现有关联的映射
	existingMap := make(map[int64]*model.ProductFeature)
	for _, item := range existingList {
		existingMap[item.FeatureId] = item
	}

	// 3. 构建新关联的映射
	newMap := make(map[int64]*types.ProductFeatureItem)
	for _, item := range req.Features {
		newMap[item.FeatureId] = &item
	}

	// 4. 在事务中执行更新操作
	err = l.svcCtx.ProductFeatureModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		// 4.1 处理需要删除的关联
		var mu sync.Mutex
		var deleteIds []int64
		err = mr.MapReduceVoid(func(source chan<- interface{}) {
			for featureId, existing := range existingMap {
				if _, exists := newMap[featureId]; !exists {
					source <- existing.Id
				}
			}
		}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
			id := item.(int64)
			mu.Lock()
			deleteIds = append(deleteIds, id)
			mu.Unlock()
		}, func(pipe <-chan struct{}, cancel func(error)) {
			// 等待所有ID收集完成
		})

		if err != nil {
			return errors.Wrapf(err, "收集待删除ID失败")
		}

		// 批量删除
		if len(deleteIds) > 0 {
			for _, id := range deleteIds {
				err = l.svcCtx.ProductFeatureModel.Delete(ctx, session, id)
				if err != nil {
					return errors.Wrapf(err, "删除产品功能关联失败, product_id: %d, id: %d",
						req.ProductId, id)
				}
			}
		}

		// 4.2 并发处理需要新增或更新的关联
		var updateErr error
		err = mr.MapReduceVoid(func(source chan<- interface{}) {
			for featureId, newItem := range newMap {
				source <- struct {
					featureId int64
					newItem   *types.ProductFeatureItem
					existing  *model.ProductFeature
				}{
					featureId: featureId,
					newItem:   newItem,
					existing:  existingMap[featureId],
				}
			}
		}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
			data := item.(struct {
				featureId int64
				newItem   *types.ProductFeatureItem
				existing  *model.ProductFeature
			})

			if data.existing != nil {
				// 更新现有关联
				data.existing.Sort = data.newItem.Sort
				data.existing.Enable = data.newItem.Enable
				data.existing.IsImportant = data.newItem.IsImportant
				_, err = l.svcCtx.ProductFeatureModel.Update(ctx, session, data.existing)
				if err != nil {
					updateErr = errors.Wrapf(err, "更新产品功能关联失败, product_id: %d, feature_id: %d",
						req.ProductId, data.featureId)
					cancel(updateErr)
					return
				}
			} else {
				// 新增关联
				newFeature := &model.ProductFeature{
					ProductId:   req.ProductId,
					FeatureId:   data.featureId,
					Sort:        data.newItem.Sort,
					Enable:      data.newItem.Enable,
					IsImportant: data.newItem.IsImportant,
				}
				_, err = l.svcCtx.ProductFeatureModel.Insert(ctx, session, newFeature)
				if err != nil {
					updateErr = errors.Wrapf(err, "新增产品功能关联失败, product_id: %d, feature_id: %d",
						req.ProductId, data.featureId)
					cancel(updateErr)
					return
				}
			}
		}, func(pipe <-chan struct{}, cancel func(error)) {
			// 等待所有更新完成
		})

		if err != nil {
			return errors.Wrapf(err, "并发更新产品功能关联失败")
		}
		if updateErr != nil {
			return updateErr
		}

		// 不自动更新产品成本价，保留用户手动设置的值
		return nil
	})

	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
			"更新产品功能关联失败, err: %v, req: %+v", err, req)
	}

	// 5. 返回结果
	return &types.AdminUpdateProductFeaturesResp{
		Success: true,
	}, nil
}
