// Package invite defines user-service invitation facts and read models.
package invite

import (
	"regexp"
	"strings"
)

const (
	// CodeStatusActive means a code can be used by new registrations.
	CodeStatusActive = "active"
	// CodeTypePrimary is the shareable per-user permanent invite code.
	CodeTypePrimary = "primary"
	// ProgressStatusPending means the invited user has not reached the configured recharge threshold.
	ProgressStatusPending = "pending"
	// ProgressStatusValid means the invited user has reached the threshold and counted once.
	ProgressStatusValid = "valid"
	// EventTypeUserInvited is emitted when an invitation relation is first bound.
	EventTypeUserInvited = "UserInvited"
	// EventTypeUserInviteBecameValid is emitted when recharge progress first crosses the policy threshold.
	EventTypeUserInviteBecameValid = "UserInviteBecameValid"
	// RechargeEventWalletRecorded is the wallet outbox event that invitation validity consumes.
	RechargeEventWalletRecorded = "WalletRechargeRecorded"
	// RechargeTypeCoinSellerTransfer is the current recharge fact produced by wallet-service coin seller transfer.
	RechargeTypeCoinSellerTransfer = "coin_seller_transfer"
	// RechargeTypeGooglePlay is the recharge fact produced by Google Play Billing.
	RechargeTypeGooglePlay = "google_play"
	// RechargeTypeGoogle is the legacy channel value carried by some Google wallet payloads.
	RechargeTypeGoogle = "google"
	// RechargeTypeMifaPay is the third-party checkout provider value for MiFaPay.
	RechargeTypeMifaPay = "mifapay"
	// RechargeTypeV5Pay is the third-party checkout provider value for V5Pay.
	RechargeTypeV5Pay = "v5pay"
	// RechargeTypeUSDTTRC20 is the third-party checkout provider value for USDT TRC20.
	RechargeTypeUSDTTRC20 = "usdt_trc20"
)

const (
	// CodeMinLength keeps user-entered invite codes short enough for mobile manual entry.
	CodeMinLength = 6
	// CodeMaxLength follows the current SQL VARCHAR boundary for invite code snapshots.
	CodeMaxLength = 64
)

var codePattern = regexp.MustCompile(`^[A-Z0-9]{6,64}$`)

// Overview is the read model returned with user profile for my-page aggregation.
type Overview struct {
	MyInviteCode             string
	InviteEnabled            bool
	InviteCount              int64
	ValidInviteCount         int64
	ValidInviteThresholdCoin int64
}

// Binding is the result of one registration/onboarding invitation bind attempt.
type Binding struct {
	Bound         bool
	InviteCode    string
	InviterUserID int64
}

// Attribution 是被邀请用户到邀请人的归因快照；活动服务只依赖这个只读事实，不直接读取邀请表。
type Attribution struct {
	Found                         bool
	AppCode                       string
	InvitedUserID                 int64
	InviterUserID                 int64
	InviteCode                    string
	BoundAtMS                     int64
	ValidityStatus                string
	AccumulatedRechargeCoinAmount int64
	RequiredRechargeCoinAmount    int64
	ValidAtMS                     int64
}

// BindCommand describes one optional invitation attribution write.
type BindCommand struct {
	AppCode         string
	InvitedUserID   int64
	InvitedRegionID int64
	InviteCode      string
	Source          string
	RequestID       string
	BoundAtMs       int64
}

// RechargeEvent is the wallet recharge fact consumed by invitation validity.
type RechargeEvent struct {
	AppCode            string
	EventID            string
	EventType          string
	TransactionID      string
	CommandID          string
	InvitedUserID      int64
	AssetType          string
	RechargeCoinAmount int64
	RechargeType       string
	OccurredAtMs       int64
	PayloadJSON        string
}

// RechargeApplyResult summarizes idempotent invitation recharge processing.
type RechargeApplyResult struct {
	Consumed bool
	Skipped  bool
	Valid    bool
	Reason   string
}

// NormalizeCode trims and uppercases user-provided invite code text.
func NormalizeCode(code string) string {
	return strings.ToUpper(strings.TrimSpace(code))
}

// ValidCode checks only syntax; ownership and active status are repository facts.
func ValidCode(code string) bool {
	code = NormalizeCode(code)
	return len(code) >= CodeMinLength && len(code) <= CodeMaxLength && codePattern.MatchString(code)
}
