package shop_series_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"
	"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 {
	allocationStore            *postgres.ShopSeriesAllocationStore
	configStore                *postgres.ShopSeriesAllocationConfigStore
	oneTimeCommissionTierStore *postgres.ShopSeriesOneTimeCommissionTierStore
	shopStore                  *postgres.ShopStore
	packageSeriesStore         *postgres.PackageSeriesStore
	packageStore               *postgres.PackageStore
}

func New(
	allocationStore *postgres.ShopSeriesAllocationStore,
	configStore *postgres.ShopSeriesAllocationConfigStore,
	oneTimeCommissionTierStore *postgres.ShopSeriesOneTimeCommissionTierStore,
	shopStore *postgres.ShopStore,
	packageSeriesStore *postgres.PackageSeriesStore,
	packageStore *postgres.PackageStore,
) *Service {
	return &Service{
		allocationStore:            allocationStore,
		configStore:                configStore,
		oneTimeCommissionTierStore: oneTimeCommissionTierStore,
		shopStore:                  shopStore,
		packageSeriesStore:         packageSeriesStore,
		packageStore:               packageStore,
	}
}

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

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

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

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

	isPlatformUser := userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform
	isFirstLevelShop := targetShop.ParentID == nil

	if isPlatformUser {
		if !isFirstLevelShop {
			return nil, errors.New(errors.CodeForbidden, "平台只能为一级店铺分配套餐")
		}
	} else {
		if isFirstLevelShop || *targetShop.ParentID != allocatorShopID {
			return nil, errors.New(errors.CodeForbidden, "只能为直属下级分配套餐")
		}
	}

	series, err := s.packageSeriesStore.GetByID(ctx, req.SeriesID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "套餐系列不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取套餐系列失败")
	}

	if userType == constants.UserTypeAgent {
		myAllocation, err := s.allocationStore.GetByShopAndSeries(ctx, allocatorShopID, req.SeriesID)
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, errors.Wrap(errors.CodeInternalError, err, "检查分配权限失败")
		}
		if myAllocation == nil || myAllocation.Status != constants.StatusEnabled {
			return nil, errors.New(errors.CodeForbidden, "您没有该套餐系列的分配权限")
		}
	}

	existing, _ := s.allocationStore.GetByShopAndSeries(ctx, req.ShopID, req.SeriesID)
	if existing != nil {
		return nil, errors.New(errors.CodeConflict, "该店铺已分配此套餐系列")
	}

	if err := s.validateOneTimeCommissionConfig(req); err != nil {
		return nil, err
	}

	allocation := &model.ShopSeriesAllocation{
		ShopID:              req.ShopID,
		SeriesID:            req.SeriesID,
		AllocatorShopID:     allocatorShopID,
		BaseCommissionMode:  req.BaseCommission.Mode,
		BaseCommissionValue: req.BaseCommission.Value,
		Status:              constants.StatusEnabled,
	}

	// 处理一次性佣金配置
	allocation.EnableOneTimeCommission = req.EnableOneTimeCommission
	if req.EnableOneTimeCommission && req.OneTimeCommissionConfig != nil {
		cfg := req.OneTimeCommissionConfig
		allocation.OneTimeCommissionType = cfg.Type
		allocation.OneTimeCommissionTrigger = cfg.Trigger
		allocation.OneTimeCommissionThreshold = cfg.Threshold
		// fixed 类型需要保存 mode 和 value
		if cfg.Type == model.OneTimeCommissionTypeFixed {
			allocation.OneTimeCommissionMode = cfg.Mode
			allocation.OneTimeCommissionValue = cfg.Value
		}
	}

	// 处理强充配置
	if req.EnableForceRecharge != nil {
		allocation.EnableForceRecharge = *req.EnableForceRecharge
	}
	if req.ForceRechargeAmount != nil {
		allocation.ForceRechargeAmount = *req.ForceRechargeAmount
	}
	if req.ForceRechargeTriggerType != nil {
		allocation.ForceRechargeTriggerType = *req.ForceRechargeTriggerType
	}

	allocation.Creator = currentUserID

	if err := s.allocationStore.Create(ctx, allocation); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建分配失败")
	}

	// 如果是梯度类型，保存梯度配置
	if req.EnableOneTimeCommission && req.OneTimeCommissionConfig != nil &&
		req.OneTimeCommissionConfig.Type == model.OneTimeCommissionTypeTiered {
		if err := s.saveOneTimeCommissionTiers(ctx, allocation.ID, req.OneTimeCommissionConfig.Tiers, currentUserID); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "创建一次性佣金梯度配置失败")
		}
	}

	return s.buildResponse(ctx, allocation, targetShop.ShopName, series.SeriesName)
}

func (s *Service) Get(ctx context.Context, id uint) (*dto.ShopSeriesAllocationResponse, error) {
	allocation, err := s.allocationStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "分配记录不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取分配记录失败")
	}

	shop, _ := s.shopStore.GetByID(ctx, allocation.ShopID)
	series, _ := s.packageSeriesStore.GetByID(ctx, allocation.SeriesID)

	shopName := ""
	seriesName := ""
	if shop != nil {
		shopName = shop.ShopName
	}
	if series != nil {
		seriesName = series.SeriesName
	}

	return s.buildResponse(ctx, allocation, shopName, seriesName)
}

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

	allocation, err := s.allocationStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "分配记录不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取分配记录失败")
	}

	configChanged := false
	if req.BaseCommission != nil {
		if allocation.BaseCommissionMode != req.BaseCommission.Mode ||
			allocation.BaseCommissionValue != req.BaseCommission.Value {
			configChanged = true
		}
		allocation.BaseCommissionMode = req.BaseCommission.Mode
		allocation.BaseCommissionValue = req.BaseCommission.Value
	}

	enableOneTimeCommission := allocation.EnableOneTimeCommission
	if req.EnableOneTimeCommission != nil {
		enableOneTimeCommission = *req.EnableOneTimeCommission
	}
	if err := s.validateOneTimeCommissionConfigForUpdate(enableOneTimeCommission, req.OneTimeCommissionConfig); err != nil {
		return nil, err
	}

	oneTimeCommissionChanged := false
	if req.EnableOneTimeCommission != nil {
		if allocation.EnableOneTimeCommission != *req.EnableOneTimeCommission {
			oneTimeCommissionChanged = true
		}
		allocation.EnableOneTimeCommission = *req.EnableOneTimeCommission
	}
	if req.OneTimeCommissionConfig != nil && allocation.EnableOneTimeCommission {
		cfg := req.OneTimeCommissionConfig
		if allocation.OneTimeCommissionType != cfg.Type ||
			allocation.OneTimeCommissionTrigger != cfg.Trigger ||
			allocation.OneTimeCommissionThreshold != cfg.Threshold ||
			allocation.OneTimeCommissionMode != cfg.Mode ||
			allocation.OneTimeCommissionValue != cfg.Value {
			oneTimeCommissionChanged = true
		}
		allocation.OneTimeCommissionType = cfg.Type
		allocation.OneTimeCommissionTrigger = cfg.Trigger
		allocation.OneTimeCommissionThreshold = cfg.Threshold
		if cfg.Type == model.OneTimeCommissionTypeFixed {
			allocation.OneTimeCommissionMode = cfg.Mode
			allocation.OneTimeCommissionValue = cfg.Value
		} else {
			allocation.OneTimeCommissionMode = ""
			allocation.OneTimeCommissionValue = 0
		}
	}

	if req.EnableForceRecharge != nil {
		allocation.EnableForceRecharge = *req.EnableForceRecharge
	}
	if req.ForceRechargeAmount != nil {
		allocation.ForceRechargeAmount = *req.ForceRechargeAmount
	}
	if req.ForceRechargeTriggerType != nil {
		allocation.ForceRechargeTriggerType = *req.ForceRechargeTriggerType
	}

	allocation.Updater = currentUserID

	if configChanged {
		if err := s.createNewConfigVersion(ctx, allocation); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "创建配置版本失败")
		}
	}

	if err := s.allocationStore.Update(ctx, allocation); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "更新分配失败")
	}

	if oneTimeCommissionChanged && req.OneTimeCommissionConfig != nil &&
		req.OneTimeCommissionConfig.Type == model.OneTimeCommissionTypeTiered {
		if err := s.oneTimeCommissionTierStore.DeleteByAllocationID(ctx, allocation.ID); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "清理旧梯度配置失败")
		}
		if err := s.saveOneTimeCommissionTiers(ctx, allocation.ID, req.OneTimeCommissionConfig.Tiers, currentUserID); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "更新一次性佣金梯度配置失败")
		}
	}

	shop, _ := s.shopStore.GetByID(ctx, allocation.ShopID)
	series, _ := s.packageSeriesStore.GetByID(ctx, allocation.SeriesID)

	shopName := ""
	seriesName := ""
	if shop != nil {
		shopName = shop.ShopName
	}
	if series != nil {
		seriesName = series.SeriesName
	}

	return s.buildResponse(ctx, allocation, shopName, seriesName)
}

func (s *Service) Delete(ctx context.Context, id uint) error {
	allocation, err := s.allocationStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "分配记录不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取分配记录失败")
	}

	hasDependent, err := s.allocationStore.HasDependentAllocations(ctx, allocation.ShopID, allocation.SeriesID)
	if err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "检查依赖关系失败")
	}
	if hasDependent {
		return errors.New(errors.CodeConflict, "存在下级依赖，无法删除")
	}

	if err := s.allocationStore.Delete(ctx, id); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "删除分配失败")
	}

	return nil
}

func (s *Service) List(ctx context.Context, req *dto.ShopSeriesAllocationListRequest) ([]*dto.ShopSeriesAllocationResponse, int64, error) {
	userType := middleware.GetUserTypeFromContext(ctx)
	shopID := middleware.GetShopIDFromContext(ctx)

	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "id DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := make(map[string]interface{})
	if req.ShopID != nil {
		filters["shop_id"] = *req.ShopID
	}
	if req.SeriesID != nil {
		filters["series_id"] = *req.SeriesID
	}
	if req.Status != nil {
		filters["status"] = *req.Status
	}
	if shopID > 0 && userType == constants.UserTypeAgent {
		filters["allocator_shop_id"] = shopID
	}

	allocations, total, err := s.allocationStore.List(ctx, opts, filters)
	if err != nil {
		return nil, 0, errors.Wrap(errors.CodeInternalError, err, "查询分配列表失败")
	}

	responses := make([]*dto.ShopSeriesAllocationResponse, len(allocations))
	for i, a := range allocations {
		shop, _ := s.shopStore.GetByID(ctx, a.ShopID)
		series, _ := s.packageSeriesStore.GetByID(ctx, a.SeriesID)

		shopName := ""
		seriesName := ""
		if shop != nil {
			shopName = shop.ShopName
		}
		if series != nil {
			seriesName = series.SeriesName
		}

		resp, _ := s.buildResponse(ctx, a, shopName, seriesName)
		responses[i] = resp
	}

	return responses, total, nil
}

func (s *Service) UpdateStatus(ctx context.Context, id uint, status int) error {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	_, err := s.allocationStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "分配记录不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取分配记录失败")
	}

	if err := s.allocationStore.UpdateStatus(ctx, id, status, currentUserID); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "更新状态失败")
	}

	return nil
}

func (s *Service) GetParentCostPrice(ctx context.Context, shopID, packageID uint) (int64, error) {
	pkg, err := s.packageStore.GetByID(ctx, packageID)
	if err != nil {
		return 0, errors.Wrap(errors.CodeInternalError, err, "获取套餐失败")
	}

	shop, err := s.shopStore.GetByID(ctx, shopID)
	if err != nil {
		return 0, errors.Wrap(errors.CodeInternalError, err, "获取店铺失败")
	}

	if shop.ParentID == nil || *shop.ParentID == 0 {
		return pkg.SuggestedCostPrice, nil
	}

	return 0, errors.New(errors.CodeInvalidParam, "自动计算成本价功能已移除，请手动设置成本价")
}

func (s *Service) buildResponse(ctx context.Context, a *model.ShopSeriesAllocation, shopName, seriesName string) (*dto.ShopSeriesAllocationResponse, error) {
	allocatorShop, _ := s.shopStore.GetByID(ctx, a.AllocatorShopID)
	allocatorShopName := ""
	if allocatorShop != nil {
		allocatorShopName = allocatorShop.ShopName
	}

	resp := &dto.ShopSeriesAllocationResponse{
		ID:                a.ID,
		ShopID:            a.ShopID,
		ShopName:          shopName,
		SeriesID:          a.SeriesID,
		SeriesName:        seriesName,
		AllocatorShopID:   a.AllocatorShopID,
		AllocatorShopName: allocatorShopName,
		BaseCommission: dto.BaseCommissionConfig{
			Mode:  a.BaseCommissionMode,
			Value: a.BaseCommissionValue,
		},
		EnableOneTimeCommission:  a.EnableOneTimeCommission,
		EnableForceRecharge:      a.EnableForceRecharge,
		ForceRechargeAmount:      a.ForceRechargeAmount,
		ForceRechargeTriggerType: a.ForceRechargeTriggerType,
		Status:                   a.Status,
		CreatedAt:                a.CreatedAt.Format(time.RFC3339),
		UpdatedAt:                a.UpdatedAt.Format(time.RFC3339),
	}

	if a.EnableOneTimeCommission {
		cfg := &dto.OneTimeCommissionConfig{
			Type:      a.OneTimeCommissionType,
			Trigger:   a.OneTimeCommissionTrigger,
			Threshold: a.OneTimeCommissionThreshold,
			Mode:      a.OneTimeCommissionMode,
			Value:     a.OneTimeCommissionValue,
		}
		if a.OneTimeCommissionType == model.OneTimeCommissionTypeTiered {
			tiers, err := s.oneTimeCommissionTierStore.ListByAllocationID(ctx, a.ID)
			if err == nil && len(tiers) > 0 {
				cfg.Tiers = make([]dto.OneTimeCommissionTierEntry, len(tiers))
				for i, t := range tiers {
					cfg.Tiers[i] = dto.OneTimeCommissionTierEntry{
						TierType:  t.TierType,
						Threshold: t.ThresholdValue,
						Mode:      t.CommissionMode,
						Value:     t.CommissionValue,
					}
				}
			}
		}
		resp.OneTimeCommissionConfig = cfg
	}

	return resp, nil
}

func (s *Service) createNewConfigVersion(ctx context.Context, allocation *model.ShopSeriesAllocation) error {
	now := time.Now()

	if err := s.configStore.InvalidateCurrent(ctx, allocation.ID, now); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "失效当前配置版本失败")
	}

	latestVersion, err := s.configStore.GetLatestVersion(ctx, allocation.ID)
	newVersion := 1
	if err == nil && latestVersion != nil {
		newVersion = latestVersion.Version + 1
	}

	newConfig := &model.ShopSeriesAllocationConfig{
		AllocationID:        allocation.ID,
		Version:             newVersion,
		BaseCommissionMode:  allocation.BaseCommissionMode,
		BaseCommissionValue: allocation.BaseCommissionValue,
		EffectiveFrom:       now,
	}

	if err := s.configStore.Create(ctx, newConfig); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "创建新配置版本失败")
	}

	return nil
}

func (s *Service) validateOneTimeCommissionConfig(req *dto.CreateShopSeriesAllocationRequest) error {
	if !req.EnableOneTimeCommission {
		return nil
	}
	if req.OneTimeCommissionConfig == nil {
		return errors.New(errors.CodeInvalidParam, "启用一次性佣金时必须提供配置")
	}
	cfg := req.OneTimeCommissionConfig
	if cfg.Type == model.OneTimeCommissionTypeFixed {
		if cfg.Mode == "" {
			return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣模式")
		}
		if cfg.Value <= 0 {
			return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣金额")
		}
	} else if cfg.Type == model.OneTimeCommissionTypeTiered {
		if len(cfg.Tiers) == 0 {
			return errors.New(errors.CodeInvalidParam, "梯度类型一次性佣金必须提供梯度档位")
		}
	}
	return nil
}

func (s *Service) validateOneTimeCommissionConfigForUpdate(enableOneTimeCommission bool, cfg *dto.OneTimeCommissionConfig) error {
	if !enableOneTimeCommission {
		return nil
	}
	if cfg == nil {
		return nil
	}
	if cfg.Type == model.OneTimeCommissionTypeFixed {
		if cfg.Mode == "" {
			return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣模式")
		}
		if cfg.Value <= 0 {
			return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣金额")
		}
	} else if cfg.Type == model.OneTimeCommissionTypeTiered {
		if len(cfg.Tiers) == 0 {
			return errors.New(errors.CodeInvalidParam, "梯度类型一次性佣金必须提供梯度档位")
		}
	}
	return nil
}

func (s *Service) saveOneTimeCommissionTiers(ctx context.Context, allocationID uint, tiers []dto.OneTimeCommissionTierEntry, userID uint) error {
	if len(tiers) == 0 {
		return nil
	}

	tierModels := make([]*model.ShopSeriesOneTimeCommissionTier, len(tiers))
	for i, t := range tiers {
		tierModels[i] = &model.ShopSeriesOneTimeCommissionTier{
			AllocationID:    allocationID,
			TierType:        t.TierType,
			ThresholdValue:  t.Threshold,
			CommissionMode:  t.Mode,
			CommissionValue: t.Value,
			Status:          constants.StatusEnabled,
		}
		tierModels[i].Creator = userID
	}

	return s.oneTimeCommissionTierStore.BatchCreate(ctx, tierModels)
}

func (s *Service) GetEffectiveConfig(ctx context.Context, allocationID uint, at time.Time) (*model.ShopSeriesAllocationConfig, error) {
	config, err := s.configStore.GetEffective(ctx, allocationID, at)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "未找到生效的配置版本")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取生效配置失败")
	}
	return config, nil
}

func (s *Service) ListConfigVersions(ctx context.Context, allocationID uint) ([]*model.ShopSeriesAllocationConfig, error) {
	_, err := s.allocationStore.GetByID(ctx, allocationID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "分配记录不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取分配记录失败")
	}

	configs, err := s.configStore.List(ctx, allocationID)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取配置版本列表失败")
	}

	return configs, nil
}
