package user

import (
	"context"

	"hyapp/pkg/appcode"
	"hyapp/pkg/idgen"
	"hyapp/pkg/xerr"
	userdomain "hyapp/services/user-service/internal/domain/user"
)

// ApplyPrettyDisplayUserID 申请临时靓号并让它在租期内覆盖当前展示号。
func (s *Service) ApplyPrettyDisplayUserID(ctx context.Context, userID int64, prettyDisplayUserID string, leaseDurationMs int64, paymentReceiptID string, requestID string) (userdomain.Identity, string, error) {
	if userID <= 0 {
		// 靓号租约必须绑定明确用户。
		return userdomain.Identity{}, "", xerr.New(xerr.InvalidArgument, "user_id is required")
	}
	if !userdomain.ValidDisplayUserID(prettyDisplayUserID) {
		// 靓号也复用 display_user_id 格式规则。
		return userdomain.Identity{}, "", xerr.New(xerr.DisplayUserIDInvalid, "display_user_id format is invalid")
	}
	if leaseDurationMs <= 0 {
		// 没有正租期无法计算过期恢复时间。
		return userdomain.Identity{}, "", xerr.New(xerr.InvalidArgument, "lease_duration_ms is required")
	}
	if paymentReceiptID == "" {
		// v1 要求先完成支付再申请靓号，避免 user-service 自己处理账务。
		return userdomain.Identity{}, "", xerr.New(xerr.DisplayUserIDPaymentRequired, "payment receipt is required")
	}
	if s.identityRepository == nil {
		// 靓号涉及多表事务，必须由 identity repository 完成。
		return userdomain.Identity{}, "", xerr.New(xerr.Unavailable, "identity repository is not configured")
	}

	// LeaseID 在服务层生成，repository 只负责原子保存和冲突判断。
	nowMs := s.now().UnixMilli()
	return s.identityRepository.ApplyPrettyDisplayUserID(ctx, userdomain.PrettyDisplayUserIDCommand{
		AppCode:          appcode.FromContext(ctx),
		LeaseID:          idgen.New("pdu_lease"),
		UserID:           userID,
		PrettyDisplayID:  prettyDisplayUserID,
		LeaseDurationMs:  leaseDurationMs,
		PaymentReceiptID: paymentReceiptID,
		Source:           "payment",
		RequestID:        requestID,
		OperatorUserID:   userID,
		NowMs:            nowMs,
	})
}

// ExpirePrettyDisplayUserID 主动触发靓号过期恢复；定时任务和懒过期应复用同一事务。
func (s *Service) ExpirePrettyDisplayUserID(ctx context.Context, userID int64, leaseID string, requestID string) (userdomain.Identity, error) {
	if userID <= 0 {
		// 过期恢复需要明确用户，lease_id 只是可选校验条件。
		return userdomain.Identity{}, xerr.New(xerr.InvalidArgument, "user_id is required")
	}
	if s.identityRepository == nil {
		// 没有 identity repository 无法恢复默认短号。
		return userdomain.Identity{}, xerr.New(xerr.Unavailable, "identity repository is not configured")
	}

	return s.identityRepository.ExpirePrettyDisplayUserID(ctx, userdomain.ExpirePrettyDisplayUserIDCommand{
		AppCode:   appcode.FromContext(ctx),
		UserID:    userID,
		LeaseID:   leaseID,
		RequestID: requestID,
		NowMs:     s.now().UnixMilli(),
	})
}

func (s *Service) refreshExpiredUser(ctx context.Context, user userdomain.User, requestID string) (userdomain.User, error) {
	nowMs := s.now().UnixMilli()
	if !user.DisplayUserIDExpired(nowMs) {
		// 当前展示号仍有效时直接返回用户快照。
		return user, nil
	}

	if s.identityRepository == nil {
		// 发现过期但无法恢复时不能继续返回过期靓号。
		return userdomain.User{}, xerr.New(xerr.Unavailable, "identity repository is not configured")
	}

	// 过期恢复必须走 identity repository 事务，同步更新 users 和短号记录。
	if _, err := s.identityRepository.ExpirePrettyDisplayUserID(ctx, userdomain.ExpirePrettyDisplayUserIDCommand{
		AppCode:   appcode.FromContext(ctx),
		UserID:    user.UserID,
		RequestID: requestID,
		NowMs:     nowMs,
	}); err != nil {
		return userdomain.User{}, err
	}

	if s.userRepository == nil {
		// 恢复后需要重新读取 users 快照，确保返回的展示号来自持久化结果。
		return userdomain.User{}, xerr.New(xerr.Unavailable, "user repository is not configured")
	}

	return s.userRepository.GetUser(ctx, user.UserID)
}
