package identity

import (
	"context"
	"database/sql"

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

func (r *Repository) assertDisplayUserIDAvailable(ctx context.Context, tx *sql.Tx, displayUserID string, userID int64, allowSameOwner bool) error {
	// FOR UPDATE 锁住目标短号记录，避免并发抢占同一个 display_user_id。
	var existingUserID int64
	err := tx.QueryRowContext(ctx, `
		SELECT user_id
		FROM user_display_user_ids
		WHERE app_code = ? AND display_user_id = ? AND status IN (?, ?, ?, ?)
		FOR UPDATE
	`, appcode.FromContext(ctx), displayUserID, string(userdomain.DisplayUserIDStatusActive), string(userdomain.DisplayUserIDStatusHeld), string(userdomain.DisplayUserIDStatusReserved), string(userdomain.DisplayUserIDStatusBlocked)).Scan(&existingUserID)
	if err != nil && err != sql.ErrNoRows {
		return err
	}
	if err != sql.ErrNoRows && allowSameOwner && existingUserID == userID {
		// 默认短号修改允许同用户幂等检查通过。
		return nil
	}
	if err != sql.ErrNoRows {
		return xerr.New(xerr.DisplayUserIDExists, "display_user_id already exists")
	}

	var existingPrettyID string
	err = tx.QueryRowContext(ctx, `
		SELECT pretty_id
		FROM pretty_display_ids
		WHERE app_code = ? AND display_user_id = ? AND status IN (?, ?, ?, ?)
		LIMIT 1
	`, appcode.FromContext(ctx), displayUserID, userdomain.PrettyDisplayIDStatusAvailable, userdomain.PrettyDisplayIDStatusAssigned, userdomain.PrettyDisplayIDStatusDisabled, userdomain.PrettyDisplayIDStatusReserved).Scan(&existingPrettyID)
	if err != nil && err != sql.ErrNoRows {
		return err
	}
	if existingPrettyID != "" {
		// 靓号池号码和后台发放靓号也属于同一个展示号唯一空间。
		return xerr.New(xerr.DisplayUserIDExists, "display_user_id already exists")
	}

	return nil
}

func (r *Repository) assertChangeCooldown(ctx context.Context, tx *sql.Tx, command userdomain.DisplayUserIDChangeCommand) error {
	// 冷却期只统计默认短号修改，不统计靓号 apply/expire。
	var lastChangedAt sql.Null[int64]
	err := tx.QueryRowContext(ctx, `
		SELECT MAX(created_at_ms)
		FROM display_user_id_change_logs
		WHERE app_code = ? AND user_id = ? AND change_type = ?
	`, appcode.Normalize(command.AppCode), command.UserID, "default_change").Scan(&lastChangedAt)
	if err != nil {
		return err
	}
	if lastChangedAt.Valid && command.ChangedAtMs-lastChangedAt.V < command.CooldownMs {
		// 仍在冷却期内时拒绝修改默认短号。
		return xerr.New(xerr.DisplayUserIDCooldown, "display_user_id change is cooling down")
	}

	return nil
}
