package user

import (
	"context"
	"strings"

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

// GetUserIdentity 按 user_id 查询当前 active 短号。
func (s *Service) GetUserIdentity(ctx context.Context, userID int64) (userdomain.Identity, error) {
	if userID <= 0 {
		// user_id 是 identity 查询的硬条件。
		return userdomain.Identity{}, xerr.New(xerr.InvalidArgument, "user_id is required")
	}
	if s.identityRepository == nil {
		// 短号相关能力需要 identity repository，不能从 users 主表临时拼。
		return userdomain.Identity{}, xerr.New(xerr.Unavailable, "identity repository is not configured")
	}

	identity, err := s.identityRepository.GetUserIdentity(ctx, userID)
	if err != nil {
		return userdomain.Identity{}, err
	}
	if identity.DisplayUserIDKind == userdomain.DisplayUserIDKindPretty && identity.DisplayUserIDExpiresAtMs > 0 && identity.DisplayUserIDExpiresAtMs <= s.now().UnixMilli() {
		// identity 查询发现靓号过期时同步恢复默认短号，避免继续返回过期展示号。
		return s.identityRepository.ExpirePrettyDisplayUserID(ctx, userdomain.ExpirePrettyDisplayUserIDCommand{
			AppCode:   appcode.FromContext(ctx),
			UserID:    userID,
			RequestID: "",
			NowMs:     s.now().UnixMilli(),
		})
	}

	return identity, nil
}

// ResolveDisplayUserID 把短号解析成系统 user_id。
func (s *Service) ResolveDisplayUserID(ctx context.Context, displayUserID string) (userdomain.Identity, error) {
	if !userdomain.ValidResolvableDisplayUserID(displayUserID) {
		// 解析入口接受默认短号和后台发放靓号；非法字符仍然提前拒绝，避免把不可输入内容传进懒过期和查询链路。
		return userdomain.Identity{}, xerr.New(xerr.DisplayUserIDInvalid, "display_user_id format is invalid")
	}
	if s.identityRepository == nil {
		// 解析短号必须走 identity repository，确保靓号过期语义生效。
		return userdomain.Identity{}, xerr.New(xerr.Unavailable, "identity repository is not configured")
	}

	// repository 会按 nowMs 触发懒过期，过期靓号不继续解析。
	return s.identityRepository.ResolveDisplayUserID(ctx, displayUserID, s.now().UnixMilli())
}

// ResolveAdminUserIdentifier 供内部后台按默认短号、当前有效展示号或系统长 user_id 精确查人。
// 它与客户端 ResolveDisplayUserID 分离，避免把 held 默认号意外恢复成登录或普通业务可解析身份。
func (s *Service) ResolveAdminUserIdentifier(ctx context.Context, userIdentifier string) (userdomain.Identity, error) {
	userIdentifier = strings.TrimSpace(userIdentifier)
	if !userdomain.ValidResolvableDisplayUserID(userIdentifier) {
		return userdomain.Identity{}, xerr.New(xerr.InvalidArgument, "user_identifier format is invalid")
	}
	if s.identityRepository == nil {
		return userdomain.Identity{}, xerr.New(xerr.Unavailable, "identity repository is not configured")
	}

	userID, err := s.identityRepository.ResolveAdminUserIdentifier(ctx, userIdentifier, s.now().UnixMilli())
	if err != nil {
		return userdomain.Identity{}, err
	}
	// repository 只决定搜索别名归属；最终复用 GetUserIdentity 返回当前 active 投影，
	// 因此用 held 默认号搜索到有靓号的用户时，响应仍展示当前有效靓号。
	return s.GetUserIdentity(ctx, userID)
}

// ChangeDisplayUserID 修改用户默认短号，并由 repository 在事务内维护当前展示快照和审计。
func (s *Service) ChangeDisplayUserID(ctx context.Context, userID int64, newDisplayUserID string, reason string, operatorUserID int64, requestID string) (userdomain.Identity, error) {
	if userID <= 0 {
		// 修改短号必须绑定明确用户。
		return userdomain.Identity{}, xerr.New(xerr.InvalidArgument, "user_id is required")
	}
	if !userdomain.ValidDisplayUserID(newDisplayUserID) {
		// 不合法短号不会进入 repository 事务。
		return userdomain.Identity{}, xerr.New(xerr.DisplayUserIDInvalid, "display_user_id format is invalid")
	}
	if s.identityRepository == nil {
		// 没有 identity repository 时无法维护旧短号释放和变更日志。
		return userdomain.Identity{}, xerr.New(xerr.Unavailable, "identity repository is not configured")
	}

	// 冷却期和可用性检查在 repository 事务内完成，避免并发抢占。
	return s.identityRepository.ChangeDisplayUserID(ctx, userdomain.DisplayUserIDChangeCommand{
		AppCode:          appcode.FromContext(ctx),
		UserID:           userID,
		NewDisplayUserID: newDisplayUserID,
		Reason:           reason,
		OperatorUserID:   operatorUserID,
		RequestID:        requestID,
		ChangedAtMs:      s.now().UnixMilli(),
		CooldownMs:       s.displayUserIDCooldown.Milliseconds(),
	})
}
