package package_series

import (
	"context"
	"fmt"
	"time"

	"gorm.io/gorm"

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

// Service 套餐系列业务服务
type Service struct {
	packageSeriesStore        *postgres.PackageSeriesStore
	shopSeriesAllocationStore *postgres.ShopSeriesAllocationStore
	packageStore              *postgres.PackageStore
}

// New 创建套餐系列服务实例
func New(packageSeriesStore *postgres.PackageSeriesStore, shopSeriesAllocationStore *postgres.ShopSeriesAllocationStore, packageStore *postgres.PackageStore) *Service {
	return &Service{
		packageSeriesStore:        packageSeriesStore,
		shopSeriesAllocationStore: shopSeriesAllocationStore,
		packageStore:              packageStore,
	}
}

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

	existing, _ := s.packageSeriesStore.GetByCode(ctx, req.SeriesCode)
	if existing != nil {
		return nil, errors.New(errors.CodeConflict, "系列编码已存在")
	}

	series := &model.PackageSeries{
		SeriesCode:                  req.SeriesCode,
		SeriesName:                  req.SeriesName,
		Description:                 req.Description,
		Status:                      constants.StatusEnabled,
		OneTimeCommissionConfigJSON: "{}",
	}
	series.Creator = currentUserID

	if req.EnableOneTimeCommission != nil {
		series.EnableOneTimeCommission = *req.EnableOneTimeCommission
	}

	if req.OneTimeCommissionConfig != nil {
		config := s.dtoToModelConfig(req.OneTimeCommissionConfig)
		config.Enable = series.EnableOneTimeCommission
		if err := series.SetOneTimeCommissionConfig(config); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "设置一次性佣金配置失败")
		}
	} else if series.EnableOneTimeCommission {
		config := &model.OneTimeCommissionConfig{Enable: true}
		if err := series.SetOneTimeCommissionConfig(config); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "设置一次性佣金配置失败")
		}
	}

	if err := s.packageSeriesStore.Create(ctx, series); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建套餐系列失败")
	}

	return s.toResponse(series), nil
}

func (s *Service) Get(ctx context.Context, id uint) (*dto.PackageSeriesResponse, error) {
	series, err := s.packageSeriesStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "套餐系列不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取套餐系列失败")
	}
	return s.toResponse(series), nil
}

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

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

	if req.SeriesName != nil {
		series.SeriesName = *req.SeriesName
	}
	if req.Description != nil {
		series.Description = *req.Description
	}
	if req.EnableOneTimeCommission != nil {
		series.EnableOneTimeCommission = *req.EnableOneTimeCommission
	}
	if req.OneTimeCommissionConfig != nil {
		config := s.dtoToModelConfig(req.OneTimeCommissionConfig)
		config.Enable = series.EnableOneTimeCommission
		if err := series.SetOneTimeCommissionConfig(config); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "设置一次性佣金配置失败")
		}
	} else if req.EnableOneTimeCommission != nil {
		existingConfig, _ := series.GetOneTimeCommissionConfig()
		if existingConfig == nil {
			existingConfig = &model.OneTimeCommissionConfig{}
		}
		existingConfig.Enable = series.EnableOneTimeCommission
		if err := series.SetOneTimeCommissionConfig(existingConfig); err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "设置一次性佣金配置失败")
		}
	}
	series.Updater = currentUserID

	if err := s.packageSeriesStore.Update(ctx, series); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "更新套餐系列失败")
	}

	return s.toResponse(series), nil
}

func (s *Service) Delete(ctx context.Context, id uint) error {
	_, err := s.packageSeriesStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "套餐系列不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取套餐系列失败")
	}

	count, err := s.packageStore.CountBySeriesID(ctx, id)
	if err != nil {
		return err
	}
	if count > 0 {
		return errors.New(errors.CodeInvalidParam, fmt.Sprintf("该系列下有 %d 个关联套餐，请先处理后再删除", count))
	}

	if err := s.packageSeriesStore.Delete(ctx, id); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "删除套餐系列失败")
	}

	return nil
}

func (s *Service) List(ctx context.Context, req *dto.PackageSeriesListRequest) ([]*dto.PackageSeriesResponse, int64, error) {
	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.SeriesName != nil {
		filters["series_name"] = *req.SeriesName
	}
	if req.Status != nil {
		filters["status"] = *req.Status
	}
	if req.EnableOneTimeCommission != nil {
		filters["enable_one_time_commission"] = *req.EnableOneTimeCommission
	}

	// 获取用户类型，代理用户需要过滤只能看到分配给自己店铺的套餐系列
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType == constants.UserTypeAgent {
		shopID := middleware.GetShopIDFromContext(ctx)
		if shopID == 0 {
			// 代理用户没有店铺，返回空结果
			return []*dto.PackageSeriesResponse{}, 0, nil
		}

		// 查询分配给该店铺的系列 ID
		allocations, err := s.shopSeriesAllocationStore.GetByShopID(ctx, shopID)
		if err != nil {
			return nil, 0, errors.Wrap(errors.CodeInternalError, err, "查询套餐系列分配失败")
		}
		if len(allocations) == 0 {
			// 没有分配任何套餐系列，返回空结果
			return []*dto.PackageSeriesResponse{}, 0, nil
		}

		// 提取系列 ID 列表
		seriesIDs := make([]uint, len(allocations))
		for i, a := range allocations {
			seriesIDs[i] = a.SeriesID
		}
		filters["series_ids"] = seriesIDs
	}

	seriesList, total, err := s.packageSeriesStore.List(ctx, opts, filters)
	if err != nil {
		return nil, 0, errors.Wrap(errors.CodeInternalError, err, "查询套餐系列列表失败")
	}

	responses := make([]*dto.PackageSeriesResponse, len(seriesList))
	for i, series := range seriesList {
		responses[i] = s.toResponse(series)
	}

	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, "未授权访问")
	}

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

	series.Status = status
	series.Updater = currentUserID

	if err := s.packageSeriesStore.Update(ctx, series); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "更新套餐系列状态失败")
	}

	return nil
}

func (s *Service) toResponse(series *model.PackageSeries) *dto.PackageSeriesResponse {
	resp := &dto.PackageSeriesResponse{
		ID:                      series.ID,
		SeriesCode:              series.SeriesCode,
		SeriesName:              series.SeriesName,
		Description:             series.Description,
		EnableOneTimeCommission: series.EnableOneTimeCommission,
		Status:                  series.Status,
		CreatedAt:               series.CreatedAt.Format(time.RFC3339),
		UpdatedAt:               series.UpdatedAt.Format(time.RFC3339),
	}

	if config, err := series.GetOneTimeCommissionConfig(); err == nil && config != nil {
		resp.OneTimeCommissionConfig = s.modelToDTO(config)
	}

	return resp
}

func (s *Service) dtoToModelConfig(dtoConfig *dto.SeriesOneTimeCommissionConfigDTO) *model.OneTimeCommissionConfig {
	if dtoConfig == nil {
		return nil
	}

	var tiers []model.OneTimeCommissionTier
	if len(dtoConfig.Tiers) > 0 {
		tiers = make([]model.OneTimeCommissionTier, len(dtoConfig.Tiers))
		for i, tier := range dtoConfig.Tiers {
			tiers[i] = model.OneTimeCommissionTier{
				Operator:  tier.Operator,
				Dimension: tier.Dimension,
				StatScope: tier.StatScope,
				Threshold: tier.Threshold,
				Amount:    tier.Amount,
			}
		}
	}

	return &model.OneTimeCommissionConfig{
		Enable:              dtoConfig.Enable,
		TriggerType:         dtoConfig.TriggerType,
		Threshold:           dtoConfig.Threshold,
		CommissionType:      dtoConfig.CommissionType,
		CommissionAmount:    dtoConfig.CommissionAmount,
		Tiers:               tiers,
		ValidityType:        dtoConfig.ValidityType,
		ValidityValue:       dtoConfig.ValidityValue,
		EnableForceRecharge: dtoConfig.EnableForceRecharge,
		ForceCalcType:       dtoConfig.ForceCalcType,
		ForceAmount:         dtoConfig.ForceAmount,
	}
}

func (s *Service) modelToDTO(config *model.OneTimeCommissionConfig) *dto.SeriesOneTimeCommissionConfigDTO {
	if config == nil {
		return nil
	}

	var tiers []dto.OneTimeCommissionTierDTO
	if len(config.Tiers) > 0 {
		tiers = make([]dto.OneTimeCommissionTierDTO, len(config.Tiers))
		for i, tier := range config.Tiers {
			tiers[i] = dto.OneTimeCommissionTierDTO{
				Operator:  tier.Operator,
				Dimension: tier.Dimension,
				StatScope: tier.StatScope,
				Threshold: tier.Threshold,
				Amount:    tier.Amount,
			}
		}
	}

	return &dto.SeriesOneTimeCommissionConfigDTO{
		Enable:              config.Enable,
		TriggerType:         config.TriggerType,
		Threshold:           config.Threshold,
		CommissionType:      config.CommissionType,
		CommissionAmount:    config.CommissionAmount,
		Tiers:               tiers,
		ValidityType:        config.ValidityType,
		ValidityValue:       config.ValidityValue,
		EnableForceRecharge: config.EnableForceRecharge,
		ForceCalcType:       config.ForceCalcType,
		ForceAmount:         config.ForceAmount,
	}
}
