package shop_package_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 {
	packageAllocationStore *postgres.ShopPackageAllocationStore
	seriesAllocationStore  *postgres.ShopSeriesAllocationStore
	priceHistoryStore      *postgres.ShopPackageAllocationPriceHistoryStore
	shopStore              *postgres.ShopStore
	packageStore           *postgres.PackageStore
}

func New(
	packageAllocationStore *postgres.ShopPackageAllocationStore,
	seriesAllocationStore *postgres.ShopSeriesAllocationStore,
	priceHistoryStore *postgres.ShopPackageAllocationPriceHistoryStore,
	shopStore *postgres.ShopStore,
	packageStore *postgres.PackageStore,
) *Service {
	return &Service{
		packageAllocationStore: packageAllocationStore,
		seriesAllocationStore:  seriesAllocationStore,
		priceHistoryStore:      priceHistoryStore,
		shopStore:              shopStore,
		packageStore:           packageStore,
	}
}

func (s *Service) Create(ctx context.Context, req *dto.CreateShopPackageAllocationRequest) (*dto.ShopPackageAllocationResponse, 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, "获取店铺失败")
	}

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

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

	seriesAllocation, err := s.seriesAllocationStore.GetByShopAndSeries(ctx, req.ShopID, pkg.SeriesID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeForbidden, "该套餐的系列未分配给此店铺")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取系列分配失败")
	}

	existing, _ := s.packageAllocationStore.GetByShopAndPackage(ctx, req.ShopID, req.PackageID)
	if existing != nil {
		return nil, errors.New(errors.CodeConflict, "该店铺已有此套餐的覆盖配置")
	}

	allocation := &model.ShopPackageAllocation{
		ShopID:       req.ShopID,
		PackageID:    req.PackageID,
		AllocationID: seriesAllocation.ID,
		CostPrice:    req.CostPrice,
		Status:       constants.StatusEnabled,
	}
	allocation.Creator = currentUserID

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

	return s.buildResponse(ctx, allocation, targetShop.ShopName, pkg.PackageName, pkg.PackageCode)
}

func (s *Service) Get(ctx context.Context, id uint) (*dto.ShopPackageAllocationResponse, error) {
	allocation, err := s.packageAllocationStore.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)
	pkg, _ := s.packageStore.GetByID(ctx, allocation.PackageID)

	shopName := ""
	packageName := ""
	packageCode := ""
	if shop != nil {
		shopName = shop.ShopName
	}
	if pkg != nil {
		packageName = pkg.PackageName
		packageCode = pkg.PackageCode
	}

	return s.buildResponse(ctx, allocation, shopName, packageName, packageCode)
}

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

	allocation, err := s.packageAllocationStore.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.CostPrice != nil {
		allocation.CostPrice = *req.CostPrice
	}
	allocation.Updater = currentUserID

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

	shop, _ := s.shopStore.GetByID(ctx, allocation.ShopID)
	pkg, _ := s.packageStore.GetByID(ctx, allocation.PackageID)

	shopName := ""
	packageName := ""
	packageCode := ""
	if shop != nil {
		shopName = shop.ShopName
	}
	if pkg != nil {
		packageName = pkg.PackageName
		packageCode = pkg.PackageCode
	}

	return s.buildResponse(ctx, allocation, shopName, packageName, packageCode)
}

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

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

	return nil
}

func (s *Service) List(ctx context.Context, req *dto.ShopPackageAllocationListRequest) ([]*dto.ShopPackageAllocationResponse, 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.ShopID != nil {
		filters["shop_id"] = *req.ShopID
	}
	if req.PackageID != nil {
		filters["package_id"] = *req.PackageID
	}
	if req.Status != nil {
		filters["status"] = *req.Status
	}

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

	responses := make([]*dto.ShopPackageAllocationResponse, len(allocations))
	for i, a := range allocations {
		shop, _ := s.shopStore.GetByID(ctx, a.ShopID)
		pkg, _ := s.packageStore.GetByID(ctx, a.PackageID)

		shopName := ""
		packageName := ""
		packageCode := ""
		if shop != nil {
			shopName = shop.ShopName
		}
		if pkg != nil {
			packageName = pkg.PackageName
			packageCode = pkg.PackageCode
		}

		resp, _ := s.buildResponse(ctx, a, shopName, packageName, packageCode)
		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.packageAllocationStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "分配记录不存在")
		}
		return errors.Wrap(errors.CodeInternalError, err, "获取分配记录失败")
	}

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

	return nil
}

func (s *Service) buildResponse(ctx context.Context, a *model.ShopPackageAllocation, shopName, packageName, packageCode string) (*dto.ShopPackageAllocationResponse, error) {
	return &dto.ShopPackageAllocationResponse{
		ID:                  a.ID,
		ShopID:              a.ShopID,
		ShopName:            shopName,
		PackageID:           a.PackageID,
		PackageName:         packageName,
		PackageCode:         packageCode,
		AllocationID:        a.AllocationID,
		CostPrice:           a.CostPrice,
		CalculatedCostPrice: 0,
		Status:              a.Status,
		CreatedAt:           a.CreatedAt.Format(time.RFC3339),
		UpdatedAt:           a.UpdatedAt.Format(time.RFC3339),
	}, nil
}

func (s *Service) UpdateCostPrice(ctx context.Context, id uint, newCostPrice int64, changeReason string) (*dto.ShopPackageAllocationResponse, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

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

	if allocation.CostPrice == newCostPrice {
		return nil, errors.New(errors.CodeInvalidParam, "新成本价与当前成本价相同")
	}

	oldCostPrice := allocation.CostPrice
	now := time.Now()

	priceHistory := &model.ShopPackageAllocationPriceHistory{
		AllocationID:  allocation.ID,
		OldCostPrice:  oldCostPrice,
		NewCostPrice:  newCostPrice,
		ChangeReason:  changeReason,
		ChangedBy:     currentUserID,
		EffectiveFrom: now,
	}
	if err := s.priceHistoryStore.Create(ctx, priceHistory); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建价格历史记录失败")
	}

	allocation.CostPrice = newCostPrice
	allocation.Updater = currentUserID
	if err := s.packageAllocationStore.Update(ctx, allocation); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "更新成本价失败")
	}

	shop, _ := s.shopStore.GetByID(ctx, allocation.ShopID)
	pkg, _ := s.packageStore.GetByID(ctx, allocation.PackageID)

	shopName := ""
	packageName := ""
	packageCode := ""
	if shop != nil {
		shopName = shop.ShopName
	}
	if pkg != nil {
		packageName = pkg.PackageName
		packageCode = pkg.PackageCode
	}

	return s.buildResponse(ctx, allocation, shopName, packageName, packageCode)
}

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

	history, err := s.priceHistoryStore.ListByAllocation(ctx, allocationID)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取价格历史失败")
	}

	return history, nil
}
