package ledger

import (
	"strings"
)

const (
	// VipProgramTypeLegacyTimed 保持 Lalu 现有的剩余时间累加会员语义。
	VipProgramTypeLegacyTimed = "legacy_timed"
	// VipProgramTypeTieredPrivilegeV1 是 Fami P1 的九级权益体系。
	VipProgramTypeTieredPrivilegeV1 = "tiered_privilege_v1"
	// VipExpiryPolicyExtendRemaining 从当前有效截止时间继续累加购买时长。
	VipExpiryPolicyExtendRemaining = "extend_remaining"
	// VipExpiryPolicyReplaceFromNow 表示高级购买立即丢弃低级剩余时间，并从当前时刻重新计时。
	VipExpiryPolicyReplaceFromNow = "replace_from_now"
	// VipDowngradePurchasePolicyReject 禁止有效会员购买更低等级。
	VipDowngradePurchasePolicyReject = "reject"
	// VipBenefitInheritanceTargetOnly 仅使用目标等级显式配置的权益集合。
	VipBenefitInheritanceTargetOnly = "target_only"
	// VipGrantModeDirectMembership 将后台赠送直接写为真实会员。
	VipGrantModeDirectMembership = "direct_membership"
	// VipGrantModeTrialCard 将后台赠送写入可自由佩戴的背包体验卡。
	VipGrantModeTrialCard = "trial_card"
	// VipTrialCardResourceType 使体验卡复用通用背包和单选装备链路。
	VipTrialCardResourceType = "vip_trial_card"
	// VipEffectiveSourceNone 表示没有有效付费会员或已佩戴体验卡。
	VipEffectiveSourceNone = "none"
	// VipEffectiveSourcePaid 表示最终权益来自真实购买会员。
	VipEffectiveSourcePaid = "paid"
	// VipEffectiveSourceTrial 表示最终权益来自当前佩戴体验卡。
	VipEffectiveSourceTrial = "trial"
	// VipTrialCardStatusActive 表示卡片未被撤销；是否过期仍以 ExpiresAtMS 判定。
	VipTrialCardStatusActive = "active"
	// VipTrialCardStatusRevoked 表示后台已撤销卡片及对应背包权益。
	VipTrialCardStatusRevoked = "revoked"
	// VipBenefitTypeDecoration 表示需要下发或佩戴资源的视觉权益。
	VipBenefitTypeDecoration = "decoration"
	// VipBenefitTypeFunction 表示由 owner service 执行的功能权限。
	VipBenefitTypeFunction = "function"
	// VipExecutionScopeWallet 表示权益由 wallet-service 执行，例如金币返现。
	VipExecutionScopeWallet = "wallet"
	// VipExecutionScopeRoom 表示权益由 Room Cell 所在 room-service 执行。
	VipExecutionScopeRoom = "room"
	// VipExecutionScopeUser 表示权益由用户资料或访客 owner 执行。
	VipExecutionScopeUser = "user"
	// VipExecutionScopeNotice 表示权益由通知投递链路执行。
	VipExecutionScopeNotice = "notice"

	// 以下编码是 P1 跨服务权限契约；数据库、钱包投影和各 owner service 必须使用同一稳定值。
	VipBenefitCodeBadgeIdentity         = "vip_badge_identity"
	VipBenefitCodeMedal                 = "vip_medal"
	VipBenefitCodeAvatarFrame           = "avatar_frame"
	VipBenefitCodeTitle                 = "vip_title"
	VipBenefitCodeChatBubble            = "chat_bubble"
	VipBenefitCodeGift                  = "vip_gift"
	VipBenefitCodeEntryEffect           = "entry_effect"
	VipBenefitCodeVisitorHistory        = "visitor_history"
	VipBenefitCodeVoiceWave             = "voice_wave"
	VipBenefitCodeProfileCard           = "profile_card"
	VipBenefitCodeCustomRoomBackground  = "custom_room_background"
	VipBenefitCodeRoomImageMessage      = "room_image_message"
	VipBenefitCodeAnimatedAvatar        = "animated_avatar"
	VipBenefitCodeAnimatedRoomCover     = "animated_room_cover"
	VipBenefitCodeMicSkin               = "mic_skin"
	VipBenefitCodeRoomBorder            = "room_border"
	VipBenefitCodeVehicle               = "vehicle"
	VipBenefitCodeColoredRoomName       = "colored_room_name"
	VipBenefitCodeColoredNickname       = "colored_nickname"
	VipBenefitCodeColoredID             = "colored_id"
	VipBenefitCodeGiftTraySkin          = "gift_tray_skin"
	VipBenefitCodeHideProfileData       = "hide_profile_data"
	VipBenefitCodeCustomAvatarFrame     = "custom_avatar_frame"
	VipBenefitCodeLeaderboardInvisible  = "leaderboard_invisible"
	VipBenefitCodeDailyCoinRebate       = "daily_coin_rebate"
	VipBenefitCodeCustomProfileCard     = "custom_profile_card"
	VipBenefitCodeAnonymousProfileVisit = "anonymous_profile_visit"
	VipBenefitCodeCustomGift            = "custom_gift"
	VipBenefitCodeRoomEntryNotice       = "room_entry_notice"
	VipBenefitCodeCustomPrettyID        = "custom_pretty_id"
	VipBenefitCodeCustomVehicle         = "custom_vehicle"
	VipBenefitCodeAntiKick              = "anti_kick"
	VipBenefitCodeAntiMute              = "anti_mute"
	VipBenefitCodeOnlineGlobalNotice    = "online_global_notice"

	// VipDailyCoinRebateStatusClaimable 表示返现仍处于当天手动领取窗口。
	VipDailyCoinRebateStatusClaimable = "claimable"
	// VipDailyCoinRebateStatusClaimed 表示金币已经原子入账，WalletTransactionID 必须非空。
	VipDailyCoinRebateStatusClaimed = "claimed"
	// VipDailyCoinRebateStatusExpired 是查询层对超过 UTC 日终但未领取记录的只读投影。
	VipDailyCoinRebateStatusExpired = "expired"
	// VipDailyCoinRebateRunStatusRunning 表示批任务仍需沿 last_user_id 继续分页。
	VipDailyCoinRebateRunStatusRunning = "running"
	// VipDailyCoinRebateRunStatusCompleted 表示当日所有候选会员已经扫描完成。
	VipDailyCoinRebateRunStatusCompleted = "completed"
)

// VipProgramConfig 是某 App 当前 VIP 状态机的完整规则，不允许调用方再按 app_code 猜规则。
type VipProgramConfig struct {
	AppCode                  string
	ProgramType              string
	LevelCount               int32
	SameLevelExpiryPolicy    string
	UpgradeExpiryPolicy      string
	DowngradePurchasePolicy  string
	BenefitInheritancePolicy string
	GrantMode                string
	TrialCardEnabled         bool
	Status                   string
	ConfigVersion            int64
	UpdatedByAdminID         int64
	CreatedAtMS              int64
	UpdatedAtMS              int64
}

// VipBenefit 是可跨服务投影和执行的权益事实；ResourceID=0 表示纯功能或尚未绑定资源。
type VipBenefit struct {
	BenefitCode    string
	Name           string
	BenefitType    string
	UnlockLevel    int32
	Status         string
	TrialEnabled   bool
	ResourceID     int64
	ResourceType   string
	ExecutionScope string
	AutoEquip      bool
	SortOrder      int32
	MetadataJSON   string
	CreatedAtMS    int64
	UpdatedAtMS    int64
	Presentation   *VipBenefitPresentation
	// Resource 只承载已通过 App、状态和类型校验的真实目录资源；nil 明确表示当前不可渲染，
	// 客户端不能再根据 benefit_code 或 VIP 等级拼接资源地址。
	Resource *VipBenefitResource
}

// VipBenefitResource 是 wallet Resource 的完整只读投影。ledger 不能反向依赖 resource domain
// （resource domain 已依赖 ledger 的钱包资产常量），因此在 VIP 聚合内保留无行为的数据结构以避免循环依赖。
type VipBenefitResource struct {
	AppCode             string
	ResourceID          int64
	ResourceCode        string
	ResourceType        string
	Name                string
	Status              string
	Grantable           bool
	ManagerGrantEnabled bool
	GrantStrategy       string
	WalletAssetType     string
	WalletAssetAmount   int64
	PriceType           string
	CoinPrice           int64
	GiftPointAmount     int64
	UsageScopes         []string
	AssetURL            string
	PreviewURL          string
	AnimationURL        string
	MetadataJSON        string
	SortOrder           int32
	CreatedByUserID     int64
	UpdatedByUserID     int64
	CreatedAtMS         int64
	UpdatedAtMS         int64
}

// VipBenefitPresentation 是 App 可直接渲染的权益表现契约。它从 metadata_json.presentation
// 投影而来，避免 Flutter 按 benefit_code 维护一份隐形 JSON 解析规则。
type VipBenefitPresentation struct {
	Description   string                   `json:"description"`
	PreviewItems  []VipBenefitPreviewItem  `json:"preview_items"`
	NumericReward *VipBenefitNumericReward `json:"numeric_reward,omitempty"`
}

// VipBenefitPreviewItem 描述一个静态或动态预览。CompositionType 明确头像合成方式，
// 头像框与声波纹无需再由客户端根据权益编码猜测布局。
type VipBenefitPreviewItem struct {
	PreviewID       string `json:"preview_id"`
	Title           string `json:"title"`
	MediaType       string `json:"media_type"`
	AssetURL        string `json:"asset_url"`
	PreviewURL      string `json:"preview_url"`
	AnimationURL    string `json:"animation_url"`
	CompositionType string `json:"composition_type"`
	SortOrder       int32  `json:"sort_order"`
}

// VipBenefitNumericReward 只负责数值展示；真实发放和结算仍由对应 owner service 执行。
type VipBenefitNumericReward struct {
	Label  string `json:"label"`
	Value  int64  `json:"value"`
	Unit   string `json:"unit"`
	Period string `json:"period"`
}

// VipRewardItem 是 VIP 资源组权益的轻量展示投影。
type VipRewardItem struct {
	ResourceID   int64
	ResourceCode string
	ResourceType string
	Name         string
	Quantity     int64
	ExpiresAtMS  int64
	AssetURL     string
	PreviewURL   string
	AnimationURL string
}

// VipLevel 是可购买 VIP 等级配置。
type VipLevel struct {
	Level                      int32
	Name                       string
	Status                     string
	PriceCoin                  int64
	DurationMS                 int64
	RewardResourceGroupID      int64
	RequiredRechargeCoinAmount int64
	UserRechargeCoinAmount     int64
	RechargeGateRequired       bool
	PurchaseLockedReason       string
	RewardItems                []VipRewardItem
	CanPurchase                bool
	SortOrder                  int32
	CreatedAtMS                int64
	UpdatedAtMS                int64
	Benefits                   []VipBenefit
	ConfigVersion              int64
}

// UserVip 是用户当前会员状态。是否有效以 ExpiresAtMS 和当前时间判断。
type UserVip struct {
	UserID        int64
	Level         int32
	Name          string
	Active        bool
	StartedAtMS   int64
	ExpiresAtMS   int64
	UpdatedAtMS   int64
	ProgramType   string
	ConfigVersion int64
}

// UserEffectiveVipLevel 是批量展示查询需要的最小 wallet owner 事实。
// 它已经应用 program 开关、paid/trial 优先级和 UTC 过期边界，调用方只能展示，不能据此授权。
type UserEffectiveVipLevel struct {
	UserID      int64
	Level       int32
	ExpiresAtMS int64
	Source      string
}

// VipTrialCard 把通用背包 entitlement 投影为 VIP 体验卡；装备切换只改变 Equipped，
// DurationMS、EffectiveAtMS 和 ExpiresAtMS 始终保留发卡时的绝对计时事实。
type VipTrialCard struct {
	TrialCardID         string
	EntitlementID       string
	ResourceID          int64
	UserID              int64
	Level               int32
	Name                string
	Status              string
	Equipped            bool
	DurationMS          int64
	EffectiveAtMS       int64
	ExpiresAtMS         int64
	RemainingDurationMS int64
	GrantSource         string
	SourceGrantID       string
	CreatedAtMS         int64
	UpdatedAtMS         int64
}

// VipUserSettings 是用户可关闭的 VIP 展示偏好。默认值必须由 wallet owner 统一构造，
// 不能让 room/gateway 因为数据库尚未物化记录而各自猜不同默认值。
type VipUserSettings struct {
	AppCode                      string
	UserID                       int64
	RoomEntryNoticeEnabled       bool
	OnlineGlobalNoticeEnabled    bool
	HideProfileDataEnabled       bool
	AnonymousProfileVisitEnabled bool
	LeaderboardInvisibleEnabled  bool
	UpdatedAtMS                  int64
}

// DefaultVipUserSettings 返回尚未物化时的产品默认：通知默认开启，
// 隐藏个人数据、匿名访问和榜单隐身默认关闭，UpdatedAtMS=0。
func DefaultVipUserSettings(appCode string, userID int64) VipUserSettings {
	return VipUserSettings{
		AppCode: appCode, UserID: userID,
		RoomEntryNoticeEnabled: true, OnlineGlobalNoticeEnabled: true,
		HideProfileDataEnabled: false, AnonymousProfileVisitEnabled: false,
		LeaderboardInvisibleEnabled: false,
	}
}

// AllowsBenefitSetting 只处理用户可关闭的五项权益；其它权益不受偏好表影响。
func (settings VipUserSettings) AllowsBenefitSetting(benefitCode string) bool {
	switch strings.ToLower(strings.TrimSpace(benefitCode)) {
	case VipBenefitCodeRoomEntryNotice:
		return settings.RoomEntryNoticeEnabled
	case VipBenefitCodeOnlineGlobalNotice:
		return settings.OnlineGlobalNoticeEnabled
	case VipBenefitCodeHideProfileData:
		return settings.HideProfileDataEnabled
	case VipBenefitCodeAnonymousProfileVisit:
		return settings.AnonymousProfileVisitEnabled
	case VipBenefitCodeLeaderboardInvisible:
		return settings.LeaderboardInvisibleEnabled
	default:
		return true
	}
}

// VipState 是调用方唯一应消费的合并状态。EffectiveBenefits 已按真实/体验来源过滤，
// 尤其不会向体验卡返回 TrialEnabled=false 的金币返现资格；可关闭通知还需结合 UserSettings。
type VipState struct {
	PaidVip           UserVip
	EquippedTrialCard *VipTrialCard
	EffectiveVip      UserVip
	EffectiveSource   string
	EffectiveBenefits []VipBenefit
	EvaluatedAtMS     int64
	ProgramConfig     VipProgramConfig
	UserSettings      VipUserSettings
}

// PurchaseVipCommand 是 App 购买或升级 VIP 的账务命令。
type PurchaseVipCommand struct {
	AppCode   string
	CommandID string
	UserID    int64
	Level     int32
}

// PurchaseVipReceipt 是购买 VIP 成功后的稳定回执。
type PurchaseVipReceipt struct {
	OrderID          string
	TransactionID    string
	Vip              UserVip
	CoinSpent        int64
	CoinBalanceAfter int64
	CoinBalance      AssetBalance
	RewardItems      []VipRewardItem
	State            VipState
}

// GrantVipCommand 是活动或后台发放 VIP 的统一入口命令。
type GrantVipCommand struct {
	AppCode        string
	CommandID      string
	TargetUserID   int64
	Level          int32
	GrantSource    string
	OperatorUserID int64
	Reason         string
}

// GrantVipReceipt 是赠送 VIP 成功后的稳定回执。
type GrantVipReceipt struct {
	TransactionID string
	Vip           UserVip
	RewardItems   []VipRewardItem
	State         VipState
}

// GrantVipTrialCardCommand 是直接按等级和绝对时长发放体验卡的幂等命令。
// ResourceID=0 表示按 level 解析同 App 预置资源；非 0 时也必须匹配该等级的 vip_trial_card。
type GrantVipTrialCardCommand struct {
	AppCode        string
	CommandID      string
	TargetUserID   int64
	Level          int32
	DurationMS     int64
	ResourceID     int64
	GrantSource    string
	OperatorUserID int64
	Reason         string
}

// GrantVipTrialCardReceipt 返回新卡和重新计算后的有效 VIP 状态；发卡本身不自动佩戴。
type GrantVipTrialCardReceipt struct {
	TrialCard    VipTrialCard
	State        VipState
	ServerTimeMS int64
}

// EquipVipTrialCardCommand 以 entitlement 精确选择背包实例，避免同资源多卡时佩戴错对象。
type EquipVipTrialCardCommand struct {
	AppCode   string
	RequestID string
	// EquipmentCommandID/ResourceID 仅由通用背包装备入口携带，用于把体验卡状态机的
	// 成功结果写入同一份装备幂等事实；专用旧接口保持为空，不改变原有 request_id 语义。
	EquipmentCommandID string
	ResourceID         int64
	UserID             int64
	EntitlementID      string
}

// UnequipVipTrialCardCommand 只清理 vip_trial_card 类型的装备事实，不回收或暂停任一卡片。
type UnequipVipTrialCardCommand struct {
	AppCode   string
	RequestID string
	UserID    int64
}

// CheckVipBenefitResult 是 owner service 执行单项特权时使用的服务端判断结果。
type CheckVipBenefitResult struct {
	Allowed               bool
	Benefit               VipBenefit
	State                 VipState
	DenialReason          string
	EvaluatedAtMS         int64
	RequiredLevel         int32
	CurrentEffectiveLevel int32
}

// AdminVipLevelCommand 是后台保存 VIP 等级配置的完整事实输入。
type AdminVipLevelCommand struct {
	Level                      int32
	Name                       string
	Status                     string
	PriceCoin                  int64
	DurationMS                 int64
	RewardResourceGroupID      int64
	RequiredRechargeCoinAmount int64
	SortOrder                  int32
	Benefits                   []VipBenefit
}

// AdminVipProgramConfigCommand 是后台保存 App 级 VIP 策略的审计输入。
type AdminVipProgramConfigCommand struct {
	Config         VipProgramConfig
	OperatorUserID int64
}

// UpdateVipUserSettingsCommand 使用指针表达 partial update；nil 字段必须保留数据库原值。
type UpdateVipUserSettingsCommand struct {
	AppCode                      string
	UserID                       int64
	RoomEntryNoticeEnabled       *bool
	OnlineGlobalNoticeEnabled    *bool
	HideProfileDataEnabled       *bool
	AnonymousProfileVisitEnabled *bool
	LeaderboardInvisibleEnabled  *bool
}

// VipDailyCoinRebateRun 是单 App、单 UTC 日唯一的配置快照与分页游标。
// LevelAmounts 只在创建 run 时从 active daily_coin_rebate 权益解析，后续分页禁止回读新配置。
type VipDailyCoinRebateRun struct {
	RunID            string
	TaskDay          string
	DayStartMS       int64
	DayEndMS         int64
	ConfigVersion    int64
	LevelAmounts     map[int32]int64
	LevelAmountsJSON string
	Status           string
	LastUserID       int64
	ScannedCount     int64
	CreatedCount     int64
	CreatedAtMS      int64
	UpdatedAtMS      int64
	CompletedAtMS    int64
}

// VipDailyCoinRebate 是日切时生成、当天手动领取的付费 VIP 返现事实。
type VipDailyCoinRebate struct {
	RebateID            string
	UserID              int64
	TaskDay             string
	VipLevel            int32
	VipName             string
	CoinAmount          int64
	Status              string
	AvailableAtMS       int64
	ExpiresAtMS         int64
	ConfigVersion       int64
	ClaimedAtMS         int64
	WalletTransactionID string
	CreatedAtMS         int64
	UpdatedAtMS         int64
}

// ProcessVipDailyCoinRebateBatchCommand 由 cron 适配器构造；NowMS 仅由 wallet-service 注入，
// repository 不信任调度方的本地时钟。
type ProcessVipDailyCoinRebateBatchCommand struct {
	AppCode   string
	TaskDay   string
	BatchSize int
	NowMS     int64
}

// ProcessVipDailyCoinRebateBatchResult 返回本页计数与持久 run，调度方据 HasMore 继续触发。
type ProcessVipDailyCoinRebateBatchResult struct {
	Run          VipDailyCoinRebateRun
	ScannedCount int
	CreatedCount int
	HasMore      bool
}

// ListVipDailyCoinRebateStatusesQuery 是用户侧返现历史分页查询；状态在读取时按 NowMS 投影。
type ListVipDailyCoinRebateStatusesQuery struct {
	AppCode   string
	UserID    int64
	Page      int
	PageSize  int
	RebateIDs []string
	NowMS     int64
}

// ClaimVipDailyCoinRebateCommand 只包含调用方可控主键；金额、等级和窗口全部从锁内返现行读取。
type ClaimVipDailyCoinRebateCommand struct {
	AppCode   string
	CommandID string
	UserID    int64
	RebateID  string
	NowMS     int64
}

// ClaimVipDailyCoinRebateReceipt 是幂等稳定回执；同 command 重放必须返回同一交易和账后余额。
type ClaimVipDailyCoinRebateReceipt struct {
	Rebate        VipDailyCoinRebate
	TransactionID string
	CoinBalance   AssetBalance
}

func NormalizeVipGrantSource(source string) string {
	switch strings.ToLower(strings.TrimSpace(source)) {
	case VipGrantSourcePurchase:
		return VipGrantSourcePurchase
	case VipGrantSourceActivity:
		return VipGrantSourceActivity
	case VipGrantSourceAdmin:
		return VipGrantSourceAdmin
	case VipGrantSourceManagerCenter:
		return VipGrantSourceManagerCenter
	default:
		return ""
	}
}
