package activitytemplate

import (
	"hyapp-admin-server/internal/integration/userclient"
	activityv1 "hyapp.local/api/proto/activity/v1"
)

type localeDTO struct {
	Locale string `json:"locale"`
	Title  string `json:"title"`
	Rules  string `json:"rules"`
}

type giftDTO struct {
	GiftID       string `json:"gift_id"`
	SortOrder    int32  `json:"sort_order"`
	Name         string `json:"name"`
	IconURL      string `json:"icon_url"`
	CoinPrice    int64  `json:"coin_price"`
	PriceVersion string `json:"price_version"`
}

// rewardItemDTO is the immutable, display-safe reward item captured at publish
// time. Admin reads this snapshot instead of joining mutable wallet catalog rows.
type rewardItemDTO struct {
	ItemType          string `json:"item_type"`
	ResourceID        int64  `json:"resource_id"`
	ResourceType      string `json:"resource_type"`
	Name              string `json:"name"`
	IconURL           string `json:"icon_url"`
	Quantity          int64  `json:"quantity"`
	DurationMS        int64  `json:"duration_ms"`
	WalletAssetType   string `json:"wallet_asset_type"`
	WalletAssetAmount int64  `json:"wallet_asset_amount"`
	SortOrder         int32  `json:"sort_order"`
}

type taskDTO struct {
	TaskKey               string          `json:"task_key"`
	TaskType              string          `json:"task_type"`
	TargetValue           int64           `json:"target_value"`
	RewardResourceGroupID int64           `json:"reward_resource_group_id"`
	SortOrder             int32           `json:"sort_order"`
	RewardSnapshotID      string          `json:"reward_snapshot_id"`
	RewardSnapshotHash    string          `json:"reward_snapshot_hash"`
	RewardName            string          `json:"reward_name"`
	RewardItems           []rewardItemDTO `json:"reward_items"`
}

type rankRewardDTO struct {
	BoardType          string          `json:"board_type"`
	RankFrom           int32           `json:"rank_from"`
	RankTo             int32           `json:"rank_to"`
	ResourceGroupID    int64           `json:"resource_group_id"`
	SortOrder          int32           `json:"sort_order"`
	RewardSnapshotID   string          `json:"reward_snapshot_id"`
	RewardSnapshotHash string          `json:"reward_snapshot_hash"`
	RewardName         string          `json:"reward_name"`
	RewardItems        []rewardItemDTO `json:"reward_items"`
}

type assetDTO struct {
	AssetKey  string `json:"asset_key"`
	Locale    string `json:"locale"`
	URL       string `json:"url"`
	MediaType string `json:"media_type"`
	SortOrder int32  `json:"sort_order"`
}

type templateSummaryDTO struct {
	AppCode          string  `json:"app_code"`
	TemplateID       string  `json:"template_id"`
	TemplateCode     string  `json:"template_code"`
	Name             string  `json:"name"`
	ActivityType     string  `json:"activity_type"`
	Status           string  `json:"status"`
	LifecycleStatus  string  `json:"lifecycle_status"`
	StartMS          int64   `json:"start_ms"`
	EndMS            int64   `json:"end_ms"`
	AllRegions       bool    `json:"all_regions"`
	RegionIDs        []int64 `json:"region_ids"`
	Revision         int64   `json:"revision"`
	PublishedVersion int64   `json:"published_version"`
	CreatedByAdminID int64   `json:"created_by_admin_id"`
	UpdatedByAdminID int64   `json:"updated_by_admin_id"`
	CreatedAtMS      int64   `json:"created_at_ms"`
	UpdatedAtMS      int64   `json:"updated_at_ms"`
	LandingPageURL   string  `json:"landing_page_url"`
}

type templateDTO struct {
	AppCode              string          `json:"app_code"`
	TemplateID           string          `json:"template_id"`
	TemplateCode         string          `json:"template_code"`
	Name                 string          `json:"name"`
	ActivityType         string          `json:"activity_type"`
	Status               string          `json:"status"`
	LifecycleStatus      string          `json:"lifecycle_status"`
	StartMS              int64           `json:"start_ms"`
	EndMS                int64           `json:"end_ms"`
	AllRegions           bool            `json:"all_regions"`
	RegionIDs            []int64         `json:"region_ids"`
	Locales              []localeDTO     `json:"locales"`
	Gifts                []giftDTO       `json:"gifts"`
	Tasks                []taskDTO       `json:"tasks"`
	DailyLeaderboardSize int32           `json:"daily_leaderboard_size"`
	TotalLeaderboardSize int32           `json:"total_leaderboard_size"`
	RankRewards          []rankRewardDTO `json:"rank_rewards"`
	Assets               []assetDTO      `json:"assets"`
	DisplayConfigJSON    string          `json:"display_config_json"`
	Revision             int64           `json:"revision"`
	PublishedVersion     int64           `json:"published_version"`
	CreatedByAdminID     int64           `json:"created_by_admin_id"`
	UpdatedByAdminID     int64           `json:"updated_by_admin_id"`
	PublishedByAdminID   int64           `json:"published_by_admin_id"`
	CreatedAtMS          int64           `json:"created_at_ms"`
	UpdatedAtMS          int64           `json:"updated_at_ms"`
	PublishedAtMS        int64           `json:"published_at_ms"`
	ArchivedAtMS         int64           `json:"archived_at_ms"`
	LandingPageURL       string          `json:"landing_page_url"`
}

type versionDTO struct {
	TemplateID         string      `json:"template_id"`
	VersionNo          int64       `json:"version_no"`
	Snapshot           templateDTO `json:"snapshot"`
	PublishedByAdminID int64       `json:"published_by_admin_id"`
	PublishedAtMS      int64       `json:"published_at_ms"`
	RuntimeFromMS      int64       `json:"runtime_from_ms"`
	RuntimeToMS        int64       `json:"runtime_to_ms"`
}

type validationIssueDTO struct {
	Field   string `json:"field"`
	Code    string `json:"code"`
	Message string `json:"message"`
}

type pageDTO struct {
	Items        any   `json:"items"`
	Page         int   `json:"page"`
	PageSize     int   `json:"page_size"`
	Total        int64 `json:"total"`
	ServerTimeMS int64 `json:"server_time_ms,omitempty"`
}

type rankPeriodDTO struct {
	TemplateID    string `json:"template_id"`
	TemplateCode  string `json:"template_code"`
	VersionNo     int64  `json:"version_no"`
	BoardType     string `json:"board_type"`
	PeriodKey     string `json:"period_key"`
	PeriodStartMS int64  `json:"period_start_ms"`
	PeriodEndMS   int64  `json:"period_end_ms"`
	SettleAfterMS int64  `json:"settle_after_ms"`
	Status        string `json:"status"`
	SettledAtMS   int64  `json:"settled_at_ms"`
}

type leaderboardEntryDTO struct {
	RankNo          int32                    `json:"rank_no"`
	UserID          int64                    `json:"user_id"`
	Score           int64                    `json:"score"`
	GiftCount       int64                    `json:"gift_count"`
	CoinAmount      int64                    `json:"coin_amount"`
	FirstScoredAtMS int64                    `json:"first_scored_at_ms"`
	Snapshot        bool                     `json:"snapshot"`
	User            *activityTemplateUserDTO `json:"user,omitempty"`
}

type leaderboardPageDTO struct {
	Period   rankPeriodDTO         `json:"period"`
	Items    []leaderboardEntryDTO `json:"items"`
	Page     int                   `json:"page"`
	PageSize int                   `json:"page_size"`
	Total    int64                 `json:"total"`
}

type rewardJobDTO struct {
	RewardJobID        string                   `json:"reward_job_id"`
	TemplateID         string                   `json:"template_id"`
	TemplateCode       string                   `json:"template_code"`
	VersionNo          int64                    `json:"version_no"`
	BoardType          string                   `json:"board_type"`
	PeriodKey          string                   `json:"period_key"`
	RankNo             int32                    `json:"rank_no"`
	UserID             int64                    `json:"user_id"`
	Score              int64                    `json:"score"`
	ResourceGroupID    int64                    `json:"resource_group_id"`
	WalletCommandID    string                   `json:"wallet_command_id"`
	WalletGrantID      string                   `json:"wallet_grant_id"`
	Status             string                   `json:"status"`
	FailureReason      string                   `json:"failure_reason"`
	AttemptCount       int32                    `json:"attempt_count"`
	MaxAttempts        int32                    `json:"max_attempts"`
	NextRetryAtMS      int64                    `json:"next_retry_at_ms"`
	CreatedAtMS        int64                    `json:"created_at_ms"`
	UpdatedAtMS        int64                    `json:"updated_at_ms"`
	GrantedAtMS        int64                    `json:"granted_at_ms"`
	RewardSnapshotID   string                   `json:"reward_snapshot_id"`
	RewardSnapshotHash string                   `json:"reward_snapshot_hash"`
	RewardName         string                   `json:"reward_name"`
	RewardItems        []rewardItemDTO          `json:"reward_items"`
	User               *activityTemplateUserDTO `json:"user,omitempty"`
}

type taskClaimDTO struct {
	ClaimID               string                   `json:"claim_id"`
	CommandID             string                   `json:"command_id"`
	TemplateID            string                   `json:"template_id"`
	TemplateCode          string                   `json:"template_code"`
	VersionNo             int64                    `json:"version_no"`
	TaskDay               string                   `json:"task_day"`
	TaskKey               string                   `json:"task_key"`
	UserID                int64                    `json:"user_id"`
	RewardResourceGroupID int64                    `json:"reward_resource_group_id"`
	WalletCommandID       string                   `json:"wallet_command_id"`
	WalletGrantID         string                   `json:"wallet_grant_id"`
	Status                string                   `json:"status"`
	FailureReason         string                   `json:"failure_reason"`
	AttemptCount          int32                    `json:"attempt_count"`
	CreatedAtMS           int64                    `json:"created_at_ms"`
	UpdatedAtMS           int64                    `json:"updated_at_ms"`
	GrantedAtMS           int64                    `json:"granted_at_ms"`
	RewardSnapshotID      string                   `json:"reward_snapshot_id"`
	RewardSnapshotHash    string                   `json:"reward_snapshot_hash"`
	RewardName            string                   `json:"reward_name"`
	RewardItems           []rewardItemDTO          `json:"reward_items"`
	EarningRegionID       int64                    `json:"earning_region_id"`
	AttributionAtMS       int64                    `json:"attribution_at_ms"`
	User                  *activityTemplateUserDTO `json:"user,omitempty"`
}

type activityTemplateUserDTO struct {
	DisplayUserID string `json:"display_user_id"`
	Username      string `json:"username"`
	Avatar        string `json:"avatar"`
}

func rankPeriodFromProto(item *activityv1.ActivityTemplateRankPeriod) rankPeriodDTO {
	if item == nil {
		return rankPeriodDTO{}
	}
	return rankPeriodDTO{
		TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(), VersionNo: item.GetVersionNo(),
		BoardType: item.GetBoardType(), PeriodKey: item.GetPeriodKey(), PeriodStartMS: item.GetPeriodStartMs(),
		PeriodEndMS: item.GetPeriodEndMs(), SettleAfterMS: item.GetSettleAfterMs(),
		Status: item.GetStatus(), SettledAtMS: item.GetSettledAtMs(),
	}
}

func leaderboardEntryFromProto(item *activityv1.ActivityTemplateLeaderboardEntry, users map[int64]*userclient.User) leaderboardEntryDTO {
	if item == nil {
		return leaderboardEntryDTO{}
	}
	out := leaderboardEntryDTO{
		RankNo: item.GetRankNo(), UserID: item.GetUserId(), Score: item.GetScore(), GiftCount: item.GetGiftCount(),
		CoinAmount: item.GetCoinAmount(), FirstScoredAtMS: item.GetFirstScoredAtMs(), Snapshot: item.GetSnapshot(),
	}
	out.User = activityTemplateUserFromClient(users[item.GetUserId()])
	return out
}

func rewardJobFromProto(item *activityv1.ActivityTemplateRewardJob, users map[int64]*userclient.User) rewardJobDTO {
	if item == nil {
		return rewardJobDTO{}
	}
	out := rewardJobDTO{
		RewardJobID: item.GetRewardJobId(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(),
		VersionNo: item.GetVersionNo(), BoardType: item.GetBoardType(), PeriodKey: item.GetPeriodKey(), RankNo: item.GetRankNo(),
		UserID: item.GetUserId(), Score: item.GetScore(), ResourceGroupID: item.GetResourceGroupId(),
		WalletCommandID: item.GetWalletCommandId(), WalletGrantID: item.GetWalletGrantId(), Status: item.GetStatus(),
		FailureReason: item.GetFailureReason(), AttemptCount: item.GetAttemptCount(), MaxAttempts: item.GetMaxAttempts(),
		NextRetryAtMS: item.GetNextRetryAtMs(), CreatedAtMS: item.GetCreatedAtMs(),
		UpdatedAtMS: item.GetUpdatedAtMs(), GrantedAtMS: item.GetGrantedAtMs(),
		RewardSnapshotID: item.GetRewardSnapshotId(), RewardSnapshotHash: item.GetRewardSnapshotHash(),
		RewardName: item.GetRewardName(), RewardItems: rewardItemsFromProto(item.GetRewardItems()),
	}
	out.User = activityTemplateUserFromClient(users[item.GetUserId()])
	return out
}

func taskClaimFromProto(item *activityv1.ActivityTemplateTaskClaim, users map[int64]*userclient.User) taskClaimDTO {
	if item == nil {
		return taskClaimDTO{RewardItems: []rewardItemDTO{}}
	}
	out := taskClaimDTO{
		ClaimID: item.GetClaimId(), CommandID: item.GetCommandId(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(),
		VersionNo: item.GetVersionNo(), TaskDay: item.GetTaskDay(), TaskKey: item.GetTaskKey(), UserID: item.GetUserId(),
		RewardResourceGroupID: item.GetRewardResourceGroupId(), WalletCommandID: item.GetWalletCommandId(), WalletGrantID: item.GetWalletGrantId(),
		Status: item.GetStatus(), FailureReason: item.GetFailureReason(), AttemptCount: item.GetAttemptCount(),
		CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), GrantedAtMS: item.GetGrantedAtMs(),
		RewardSnapshotID: item.GetRewardSnapshotId(), RewardSnapshotHash: item.GetRewardSnapshotHash(), RewardName: item.GetRewardName(),
		RewardItems: rewardItemsFromProto(item.GetRewardItems()), EarningRegionID: item.GetEarningRegionId(), AttributionAtMS: item.GetAttributionAtMs(),
	}
	out.User = activityTemplateUserFromClient(users[item.GetUserId()])
	return out
}

func rewardItemsFromProto(items []*activityv1.ActivityTemplateRewardItem) []rewardItemDTO {
	out := make([]rewardItemDTO, 0, len(items))
	for _, item := range items {
		if item == nil {
			continue
		}
		out = append(out, rewardItemDTO{
			ItemType: item.GetItemType(), ResourceID: item.GetResourceId(), ResourceType: item.GetResourceType(),
			Name: item.GetName(), IconURL: item.GetIconUrl(), Quantity: item.GetQuantity(), DurationMS: item.GetDurationMs(),
			WalletAssetType: item.GetWalletAssetType(), WalletAssetAmount: item.GetWalletAssetAmount(), SortOrder: item.GetSortOrder(),
		})
	}
	return out
}

func activityTemplateUserFromClient(item *userclient.User) *activityTemplateUserDTO {
	if item == nil {
		return nil
	}
	return &activityTemplateUserDTO{DisplayUserID: item.DisplayUserID, Username: item.Username, Avatar: item.Avatar}
}

func summaryFromProto(item *activityv1.ActivityTemplateSummary) templateSummaryDTO {
	if item == nil {
		return templateSummaryDTO{RegionIDs: []int64{}}
	}
	return templateSummaryDTO{
		AppCode: item.GetAppCode(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(),
		Name: item.GetName(), ActivityType: item.GetActivityType(), Status: item.GetStatus(), LifecycleStatus: item.GetLifecycleStatus(),
		StartMS: item.GetStartMs(), EndMS: item.GetEndMs(), AllRegions: item.GetAllRegions(), RegionIDs: cloneInt64Slice(item.GetRegionIds()),
		Revision: item.GetRevision(), PublishedVersion: item.GetPublishedVersion(),
		CreatedByAdminID: item.GetCreatedByAdminId(), UpdatedByAdminID: item.GetUpdatedByAdminId(),
		CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(),
	}
}

func templateFromProto(item *activityv1.ActivityTemplate) templateDTO {
	if item == nil {
		return templateDTO{RegionIDs: []int64{}, Locales: []localeDTO{}, Gifts: []giftDTO{}, Tasks: []taskDTO{}, RankRewards: []rankRewardDTO{}, Assets: []assetDTO{}}
	}
	out := templateDTO{
		AppCode: item.GetAppCode(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(), Name: item.GetName(),
		ActivityType: item.GetActivityType(), Status: item.GetStatus(), LifecycleStatus: item.GetLifecycleStatus(),
		StartMS: item.GetStartMs(), EndMS: item.GetEndMs(), AllRegions: item.GetAllRegions(), RegionIDs: cloneInt64Slice(item.GetRegionIds()),
		Locales: make([]localeDTO, 0, len(item.GetLocales())), Gifts: make([]giftDTO, 0, len(item.GetGifts())),
		Tasks: make([]taskDTO, 0, len(item.GetTasks())), RankRewards: make([]rankRewardDTO, 0, len(item.GetRankRewards())),
		Assets: make([]assetDTO, 0, len(item.GetAssets())), DailyLeaderboardSize: item.GetDailyLeaderboardSize(),
		TotalLeaderboardSize: item.GetTotalLeaderboardSize(), DisplayConfigJSON: item.GetDisplayConfigJson(),
		Revision: item.GetRevision(), PublishedVersion: item.GetPublishedVersion(),
		CreatedByAdminID: item.GetCreatedByAdminId(), UpdatedByAdminID: item.GetUpdatedByAdminId(), PublishedByAdminID: item.GetPublishedByAdminId(),
		CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), PublishedAtMS: item.GetPublishedAtMs(), ArchivedAtMS: item.GetArchivedAtMs(),
	}
	for _, locale := range item.GetLocales() {
		out.Locales = append(out.Locales, localeDTO{Locale: locale.GetLocale(), Title: locale.GetTitle(), Rules: locale.GetRules()})
	}
	for _, gift := range item.GetGifts() {
		out.Gifts = append(out.Gifts, giftDTO{GiftID: gift.GetGiftId(), SortOrder: gift.GetSortOrder(), Name: gift.GetName(), IconURL: gift.GetIconUrl(), CoinPrice: gift.GetCoinPrice(), PriceVersion: gift.GetPriceVersion()})
	}
	for _, task := range item.GetTasks() {
		out.Tasks = append(out.Tasks, taskDTO{
			TaskKey: task.GetTaskKey(), TaskType: task.GetTaskType(), TargetValue: task.GetTargetValue(),
			RewardResourceGroupID: task.GetRewardResourceGroupId(), SortOrder: task.GetSortOrder(),
			RewardSnapshotID: task.GetRewardSnapshotId(), RewardSnapshotHash: task.GetRewardSnapshotHash(),
			RewardName: task.GetRewardName(), RewardItems: rewardItemsFromProto(task.GetRewardItems()),
		})
	}
	for _, reward := range item.GetRankRewards() {
		out.RankRewards = append(out.RankRewards, rankRewardDTO{
			BoardType: reward.GetBoardType(), RankFrom: reward.GetRankFrom(), RankTo: reward.GetRankTo(),
			ResourceGroupID: reward.GetResourceGroupId(), SortOrder: reward.GetSortOrder(),
			RewardSnapshotID: reward.GetRewardSnapshotId(), RewardSnapshotHash: reward.GetRewardSnapshotHash(),
			RewardName: reward.GetRewardName(), RewardItems: rewardItemsFromProto(reward.GetRewardItems()),
		})
	}
	for _, asset := range item.GetAssets() {
		out.Assets = append(out.Assets, assetDTO{AssetKey: asset.GetAssetKey(), Locale: asset.GetLocale(), URL: asset.GetUrl(), MediaType: asset.GetMediaType(), SortOrder: asset.GetSortOrder()})
	}
	return out
}

func cloneInt64Slice(items []int64) []int64 {
	out := make([]int64, len(items))
	copy(out, items)
	return out
}
