package shop_package_batch_allocation

import (
	"context"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"gorm.io/gorm"
)

type Service struct {
	db                     *gorm.DB
	packageStore           *postgres.PackageStore
	seriesAllocationStore  *postgres.ShopSeriesAllocationStore
	packageAllocationStore *postgres.ShopPackageAllocationStore
	configStore            *postgres.ShopSeriesAllocationConfigStore
	commissionStatsStore   *postgres.ShopSeriesCommissionStatsStore
	shopStore              *postgres.ShopStore
}

func New(
	db *gorm.DB,
	packageStore *postgres.PackageStore,
	seriesAllocationStore *postgres.ShopSeriesAllocationStore,
	packageAllocationStore *postgres.ShopPackageAllocationStore,
	configStore *postgres.ShopSeriesAllocationConfigStore,
	commissionStatsStore *postgres.ShopSeriesCommissionStatsStore,
	shopStore *postgres.ShopStore,
) *Service {
	return &Service{
		db:                     db,
		packageStore:           packageStore,
		seriesAllocationStore:  seriesAllocationStore,
		packageAllocationStore: packageAllocationStore,
		configStore:            configStore,
		commissionStatsStore:   commissionStatsStore,
		shopStore:              shopStore,
	}
}

func (s *Service) BatchAllocate(ctx context.Context, req *dto.BatchAllocatePackagesRequest) error {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	userType := middleware.GetUserTypeFromContext(ctx)
	allocatorShopID := middleware.GetShopIDFromContext(ctx)

	if userType == constants.UserTypeAgent && allocatorShopID == 0 {
		return errors.New(errors.CodeUnauthorized, "当前用户不属于任何店铺")
	}

	targetShop, err := s.shopStore.GetByID(ctx, req.ShopID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "目标店铺不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取目标店铺失败")
	}

	if userType == constants.UserTypeAgent {
		if targetShop.ParentID == nil || *targetShop.ParentID != allocatorShopID {
			return errors.New(errors.CodeForbidden, "只能分配给直属下级店铺")
		}
	}

	packages, err := s.getEnabledPackagesBySeries(ctx, req.SeriesID)
	if err != nil {
		return err
	}

	if len(packages) == 0 {
		return errors.New(errors.CodeInvalidParam, "该系列下没有启用的套餐")
	}

	return s.db.Transaction(func(tx *gorm.DB) error {
		seriesAllocation := &model.ShopSeriesAllocation{
			BaseModel:           model.BaseModel{Creator: currentUserID, Updater: currentUserID},
			ShopID:              req.ShopID,
			SeriesID:            req.SeriesID,
			AllocatorShopID:     allocatorShopID,
			BaseCommissionMode:  req.BaseCommission.Mode,
			BaseCommissionValue: req.BaseCommission.Value,
			Status:              constants.StatusEnabled,
		}

		if err := tx.Create(seriesAllocation).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "创建系列分配失败")
		}

		now := time.Now()
		config := &model.ShopSeriesAllocationConfig{
			AllocationID:        seriesAllocation.ID,
			Version:             1,
			BaseCommissionMode:  req.BaseCommission.Mode,
			BaseCommissionValue: req.BaseCommission.Value,
			EffectiveFrom:       now,
		}

		if err := tx.Create(config).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "创建配置版本失败")
		}

		packageAllocations := make([]*model.ShopPackageAllocation, 0, len(packages))
		for _, pkg := range packages {
			costPrice := pkg.SuggestedCostPrice
			if req.PriceAdjustment != nil {
				costPrice = s.calculateAdjustedPrice(pkg.SuggestedCostPrice, req.PriceAdjustment)
			}

			allocation := &model.ShopPackageAllocation{
				BaseModel:    model.BaseModel{Creator: currentUserID, Updater: currentUserID},
				ShopID:       req.ShopID,
				PackageID:    pkg.ID,
				AllocationID: seriesAllocation.ID,
				CostPrice:    costPrice,
				Status:       constants.StatusEnabled,
			}
			packageAllocations = append(packageAllocations, allocation)
		}

		if err := tx.CreateInBatches(packageAllocations, 100).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "批量创建套餐分配失败")
		}

		return nil
	})
}

func (s *Service) getEnabledPackagesBySeries(ctx context.Context, seriesID uint) ([]*model.Package, error) {
	filters := map[string]interface{}{
		"series_id":    seriesID,
		"status":       constants.StatusEnabled,
		"shelf_status": 1,
	}

	packages, _, err := s.packageStore.List(ctx, nil, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取套餐列表失败")
	}

	return packages, nil
}

func (s *Service) calculateAdjustedPrice(basePrice int64, adjustment *dto.PriceAdjustment) int64 {
	if adjustment == nil {
		return basePrice
	}

	if adjustment.Type == "fixed" {
		return basePrice + adjustment.Value
	}

	return basePrice + (basePrice * adjustment.Value / 1000)
}
