package resource

import (
	"encoding/json"
	"strings"

	walletv1 "hyapp.local/api/proto/wallet/v1"
)

type resourceDTO struct {
	AppCode             string   `json:"appCode"`
	ResourceID          int64    `json:"resourceId"`
	ResourceCode        string   `json:"resourceCode"`
	ResourceType        string   `json:"resourceType"`
	Name                string   `json:"name"`
	Status              string   `json:"status"`
	Grantable           bool     `json:"grantable"`
	ManagerGrantEnabled bool     `json:"managerGrantEnabled"`
	GrantStrategy       string   `json:"grantStrategy"`
	WalletAssetType     string   `json:"walletAssetType"`
	WalletAssetAmount   int64    `json:"walletAssetAmount"`
	PriceType           string   `json:"priceType"`
	CoinPrice           int64    `json:"coinPrice"`
	AvatarFrameKind     string   `json:"avatarFrameKind,omitempty"`
	BadgeForm           string   `json:"badgeForm,omitempty"`
	BadgeKind           string   `json:"badgeKind,omitempty"`
	LevelTrack          string   `json:"levelTrack,omitempty"`
	UsageScopes         []string `json:"usageScopes"`
	AssetURL            string   `json:"assetUrl"`
	PreviewURL          string   `json:"previewUrl"`
	AnimationURL        string   `json:"animationUrl"`
	MetadataJSON        string   `json:"metadataJson"`
	SortOrder           int32    `json:"sortOrder"`
	CreatedByUserID     int64    `json:"createdByUserId"`
	UpdatedByUserID     int64    `json:"updatedByUserId"`
	CreatedAtMS         int64    `json:"createdAtMs"`
	UpdatedAtMS         int64    `json:"updatedAtMs"`
}

type resourceGroupItemDTO struct {
	GroupItemID       int64        `json:"groupItemId"`
	ItemType          string       `json:"itemType"`
	ResourceID        int64        `json:"resourceId"`
	Resource          *resourceDTO `json:"resource,omitempty"`
	WalletAssetType   string       `json:"walletAssetType"`
	WalletAssetAmount int64        `json:"walletAssetAmount"`
	Quantity          int64        `json:"quantity"`
	DurationMS        int64        `json:"durationMs"`
	SortOrder         int32        `json:"sortOrder"`
	CreatedAtMS       int64        `json:"createdAtMs"`
	UpdatedAtMS       int64        `json:"updatedAtMs"`
}

type resourceGroupDTO struct {
	AppCode         string                 `json:"appCode"`
	GroupID         int64                  `json:"groupId"`
	GroupCode       string                 `json:"groupCode"`
	Name            string                 `json:"name"`
	Status          string                 `json:"status"`
	Description     string                 `json:"description"`
	SortOrder       int32                  `json:"sortOrder"`
	Items           []resourceGroupItemDTO `json:"items"`
	CreatedByUserID int64                  `json:"createdByUserId"`
	UpdatedByUserID int64                  `json:"updatedByUserId"`
	CreatedAtMS     int64                  `json:"createdAtMs"`
	UpdatedAtMS     int64                  `json:"updatedAtMs"`
}

type giftDTO struct {
	AppCode          string      `json:"appCode"`
	GiftID           string      `json:"giftId"`
	ResourceID       int64       `json:"resourceId"`
	Resource         resourceDTO `json:"resource"`
	Status           string      `json:"status"`
	Name             string      `json:"name"`
	SortOrder        int32       `json:"sortOrder"`
	PresentationJSON string      `json:"presentationJson"`
	PriceVersion     string      `json:"priceVersion"`
	GiftTypeCode     string      `json:"giftTypeCode"`
	VIPLevel         int32       `json:"vipLevel"`
	CPRelationType   string      `json:"cpRelationType"`
	ChargeAssetType  string      `json:"chargeAssetType"`
	CoinPrice        int64       `json:"coinPrice"`
	EffectiveFromMS  int64       `json:"effectiveFromMs"`
	EffectiveToMS    int64       `json:"effectiveToMs"`
	EffectTypes      []string    `json:"effectTypes"`
	CreatedByUserID  int64       `json:"createdByUserId"`
	UpdatedByUserID  int64       `json:"updatedByUserId"`
	CreatedAtMS      int64       `json:"createdAtMs"`
	UpdatedAtMS      int64       `json:"updatedAtMs"`
	RegionIDs        []int64     `json:"regionIds"`
}

type giftTypeDTO struct {
	AppCode         string `json:"appCode"`
	TabKey          string `json:"tabKey"`
	DisplayName     string `json:"displayName"`
	TabName         string `json:"tabName"`
	Status          string `json:"status"`
	SortOrder       int32  `json:"sortOrder"`
	CreatedByUserID int64  `json:"createdByUserId"`
	UpdatedByUserID int64  `json:"updatedByUserId"`
	CreatedAtMS     int64  `json:"createdAtMs"`
	UpdatedAtMS     int64  `json:"updatedAtMs"`
}

type emojiPackDTO struct {
	AppCode      string  `json:"appCode"`
	ResourceID   int64   `json:"resourceId"`
	ResourceCode string  `json:"resourceCode"`
	Name         string  `json:"name"`
	Status       string  `json:"status"`
	Category     string  `json:"category"`
	PricingType  string  `json:"pricingType"`
	CoverURL     string  `json:"coverUrl"`
	AnimationURL string  `json:"animationUrl"`
	RegionIDs    []int64 `json:"regionIds"`
	SortOrder    int32   `json:"sortOrder"`
	CreatedAtMS  int64   `json:"createdAtMs"`
	UpdatedAtMS  int64   `json:"updatedAtMs"`
}

type grantItemDTO struct {
	GrantItemID          int64  `json:"grantItemId"`
	GrantID              string `json:"grantId"`
	ResourceID           int64  `json:"resourceId"`
	ResourceSnapshotJSON string `json:"resourceSnapshotJson"`
	ResourceCoverURL     string `json:"resourceCoverUrl,omitempty"`
	Quantity             int64  `json:"quantity"`
	DurationMS           int64  `json:"durationMs"`
	ResultType           string `json:"resultType"`
	WalletTransactionID  string `json:"walletTransactionId"`
	EntitlementID        string `json:"entitlementId"`
	CreatedAtMS          int64  `json:"createdAtMs"`
}

type grantDTO struct {
	AppCode          string         `json:"appCode"`
	GrantID          string         `json:"grantId"`
	CommandID        string         `json:"commandId"`
	TargetUserID     int64          `json:"targetUserId,string"`
	TargetUser       *grantUserDTO  `json:"targetUser,omitempty"`
	GrantSource      string         `json:"grantSource"`
	GrantSubjectType string         `json:"grantSubjectType"`
	GrantSubjectID   string         `json:"grantSubjectId"`
	Status           string         `json:"status"`
	Reason           string         `json:"reason"`
	OperatorUserID   int64          `json:"operatorUserId"`
	Operator         *operatorDTO   `json:"operator,omitempty"`
	RevokedAtMS      int64          `json:"revokedAtMs"`
	RevokedByUserID  int64          `json:"revokedByUserId,string"`
	RevokeReason     string         `json:"revokeReason"`
	Items            []grantItemDTO `json:"items"`
	CreatedAtMS      int64          `json:"createdAtMs"`
	UpdatedAtMS      int64          `json:"updatedAtMs"`
}

type grantUserDTO struct {
	UserID               int64  `json:"userId,string"`
	DisplayUserID        string `json:"displayUserId,omitempty"`
	DefaultDisplayUserID string `json:"defaultDisplayUserId,omitempty"`
	PrettyDisplayUserID  string `json:"prettyDisplayUserId,omitempty"`
	PrettyID             string `json:"prettyId,omitempty"`
	Username             string `json:"username,omitempty"`
	Avatar               string `json:"avatar,omitempty"`
}

type operatorDTO struct {
	Source        string `json:"source"`
	UserID        int64  `json:"userId,string,omitempty"`
	DisplayUserID string `json:"displayUserId,omitempty"`
	Username      string `json:"username,omitempty"`
	Name          string `json:"name,omitempty"`
	Avatar        string `json:"avatar,omitempty"`
}

type resourceShopItemDTO struct {
	AppCode         string      `json:"appCode"`
	ShopItemID      int64       `json:"shopItemId"`
	ResourceID      int64       `json:"resourceId"`
	Resource        resourceDTO `json:"resource"`
	Status          string      `json:"status"`
	DurationDays    int32       `json:"durationDays"`
	PriceType       string      `json:"priceType"`
	CoinPrice       int64       `json:"coinPrice"`
	EffectiveFromMS int64       `json:"effectiveFromMs"`
	EffectiveToMS   int64       `json:"effectiveToMs"`
	SortOrder       int32       `json:"sortOrder"`
	CreatedByUserID int64       `json:"createdByUserId"`
	UpdatedByUserID int64       `json:"updatedByUserId"`
	CreatedAtMS     int64       `json:"createdAtMs"`
	UpdatedAtMS     int64       `json:"updatedAtMs"`
}

type resourceShopPurchaseOrderDTO struct {
	AppCode             string        `json:"appCode"`
	OrderID             string        `json:"orderId"`
	CommandID           string        `json:"commandId"`
	UserID              int64         `json:"userId,string"`
	User                *grantUserDTO `json:"user,omitempty"`
	ShopItemID          int64         `json:"shopItemId"`
	ResourceID          int64         `json:"resourceId"`
	Resource            resourceDTO   `json:"resource"`
	DurationDays        int32         `json:"durationDays"`
	PriceCoin           int64         `json:"priceCoin"`
	Status              string        `json:"status"`
	WalletTransactionID string        `json:"walletTransactionId"`
	ResourceGrantID     string        `json:"resourceGrantId"`
	EntitlementID       string        `json:"entitlementId"`
	CreatedAtMS         int64         `json:"createdAtMs"`
	UpdatedAtMS         int64         `json:"updatedAtMs"`
}

func resourceFromProto(item *walletv1.Resource) resourceDTO {
	if item == nil {
		return resourceDTO{}
	}
	return resourceDTO{
		AppCode:             item.GetAppCode(),
		ResourceID:          item.GetResourceId(),
		ResourceCode:        item.GetResourceCode(),
		ResourceType:        item.GetResourceType(),
		Name:                item.GetName(),
		Status:              item.GetStatus(),
		Grantable:           item.GetGrantable(),
		ManagerGrantEnabled: item.GetManagerGrantEnabled(),
		GrantStrategy:       item.GetGrantStrategy(),
		WalletAssetType:     item.GetWalletAssetType(),
		WalletAssetAmount:   item.GetWalletAssetAmount(),
		PriceType:           item.GetPriceType(),
		CoinPrice:           item.GetCoinPrice(),
		AvatarFrameKind:     avatarFrameKindForResource(item.GetResourceType(), item.GetMetadataJson()),
		BadgeForm:           badgeFormForResource(item.GetResourceType(), item.GetMetadataJson()),
		BadgeKind:           badgeKindForResource(item.GetResourceType(), item.GetMetadataJson()),
		LevelTrack:          levelTrackForResource(item.GetResourceType(), item.GetMetadataJson()),
		UsageScopes:         item.GetUsageScopes(),
		AssetURL:            item.GetAssetUrl(),
		PreviewURL:          item.GetPreviewUrl(),
		AnimationURL:        item.GetAnimationUrl(),
		MetadataJSON:        item.GetMetadataJson(),
		SortOrder:           item.GetSortOrder(),
		CreatedByUserID:     item.GetCreatedByUserId(),
		UpdatedByUserID:     item.GetUpdatedByUserId(),
		CreatedAtMS:         item.GetCreatedAtMs(),
		UpdatedAtMS:         item.GetUpdatedAtMs(),
	}
}

func resourceGroupFromProto(group *walletv1.ResourceGroup) resourceGroupDTO {
	if group == nil {
		return resourceGroupDTO{}
	}
	items := make([]resourceGroupItemDTO, 0, len(group.GetItems()))
	for _, item := range group.GetItems() {
		items = append(items, resourceGroupItemDTO{
			GroupItemID:       item.GetGroupItemId(),
			ItemType:          item.GetItemType(),
			ResourceID:        item.GetResourceId(),
			Resource:          resourcePointerFromProto(item.GetResource()),
			WalletAssetType:   item.GetWalletAssetType(),
			WalletAssetAmount: item.GetWalletAssetAmount(),
			Quantity:          item.GetQuantity(),
			DurationMS:        item.GetDurationMs(),
			SortOrder:         item.GetSortOrder(),
			CreatedAtMS:       item.GetCreatedAtMs(),
			UpdatedAtMS:       item.GetUpdatedAtMs(),
		})
	}
	return resourceGroupDTO{
		AppCode:         group.GetAppCode(),
		GroupID:         group.GetGroupId(),
		GroupCode:       group.GetGroupCode(),
		Name:            group.GetName(),
		Status:          group.GetStatus(),
		Description:     group.GetDescription(),
		SortOrder:       group.GetSortOrder(),
		Items:           items,
		CreatedByUserID: group.GetCreatedByUserId(),
		UpdatedByUserID: group.GetUpdatedByUserId(),
		CreatedAtMS:     group.GetCreatedAtMs(),
		UpdatedAtMS:     group.GetUpdatedAtMs(),
	}
}

func resourcePointerFromProto(item *walletv1.Resource) *resourceDTO {
	if item == nil || item.GetResourceId() == 0 {
		return nil
	}
	data := resourceFromProto(item)
	return &data
}

func resourceShopItemFromProto(item *walletv1.ResourceShopItem) resourceShopItemDTO {
	if item == nil {
		return resourceShopItemDTO{}
	}
	return resourceShopItemDTO{
		AppCode:         item.GetAppCode(),
		ShopItemID:      item.GetShopItemId(),
		ResourceID:      item.GetResourceId(),
		Resource:        resourceFromProto(item.GetResource()),
		Status:          item.GetStatus(),
		DurationDays:    item.GetDurationDays(),
		PriceType:       item.GetPriceType(),
		CoinPrice:       item.GetCoinPrice(),
		EffectiveFromMS: item.GetEffectiveFromMs(),
		EffectiveToMS:   item.GetEffectiveToMs(),
		SortOrder:       item.GetSortOrder(),
		CreatedByUserID: item.GetCreatedByUserId(),
		UpdatedByUserID: item.GetUpdatedByUserId(),
		CreatedAtMS:     item.GetCreatedAtMs(),
		UpdatedAtMS:     item.GetUpdatedAtMs(),
	}
}

func resourceShopPurchaseOrderFromProto(item *walletv1.ResourceShopPurchaseOrder) resourceShopPurchaseOrderDTO {
	if item == nil {
		return resourceShopPurchaseOrderDTO{}
	}
	return resourceShopPurchaseOrderDTO{
		AppCode:             item.GetAppCode(),
		OrderID:             item.GetOrderId(),
		CommandID:           item.GetCommandId(),
		UserID:              item.GetUserId(),
		ShopItemID:          item.GetShopItemId(),
		ResourceID:          item.GetResourceId(),
		Resource:            resourceFromProto(item.GetResource()),
		DurationDays:        item.GetDurationDays(),
		PriceCoin:           item.GetPriceCoin(),
		Status:              item.GetStatus(),
		WalletTransactionID: item.GetWalletTransactionId(),
		ResourceGrantID:     item.GetResourceGrantId(),
		EntitlementID:       item.GetEntitlementId(),
		CreatedAtMS:         item.GetCreatedAtMs(),
		UpdatedAtMS:         item.GetUpdatedAtMs(),
	}
}

func giftFromProto(gift *walletv1.GiftConfig) giftDTO {
	if gift == nil {
		return giftDTO{}
	}
	return giftDTO{
		AppCode:          gift.GetAppCode(),
		GiftID:           gift.GetGiftId(),
		ResourceID:       gift.GetResourceId(),
		Resource:         resourceFromProto(gift.GetResource()),
		Status:           gift.GetStatus(),
		Name:             gift.GetName(),
		SortOrder:        gift.GetSortOrder(),
		PresentationJSON: gift.GetPresentationJson(),
		PriceVersion:     gift.GetPriceVersion(),
		GiftTypeCode:     gift.GetGiftTypeCode(),
		VIPLevel:         gift.GetVipLevel(),
		CPRelationType:   gift.GetCpRelationType(),
		ChargeAssetType:  gift.GetChargeAssetType(),
		CoinPrice:        gift.GetCoinPrice(),
		EffectiveFromMS:  gift.GetEffectiveFromMs(),
		EffectiveToMS:    gift.GetEffectiveToMs(),
		EffectTypes:      gift.GetEffectTypes(),
		CreatedByUserID:  gift.GetCreatedByUserId(),
		UpdatedByUserID:  gift.GetUpdatedByUserId(),
		CreatedAtMS:      gift.GetCreatedAtMs(),
		UpdatedAtMS:      gift.GetUpdatedAtMs(),
		RegionIDs:        gift.GetRegionIds(),
	}
}

func giftTypeFromProto(item *walletv1.GiftTypeConfig) giftTypeDTO {
	if item == nil {
		return giftTypeDTO{}
	}
	return giftTypeDTO{
		AppCode:         item.GetAppCode(),
		TabKey:          item.GetTypeCode(),
		DisplayName:     item.GetName(),
		TabName:         item.GetTabKey(),
		Status:          item.GetStatus(),
		SortOrder:       item.GetSortOrder(),
		CreatedByUserID: item.GetCreatedByUserId(),
		UpdatedByUserID: item.GetUpdatedByUserId(),
		CreatedAtMS:     item.GetCreatedAtMs(),
		UpdatedAtMS:     item.GetUpdatedAtMs(),
	}
}

func emojiPackFromProto(item *walletv1.Resource) emojiPackDTO {
	if item == nil {
		return emojiPackDTO{}
	}
	metadata := emojiPackMetadataFromJSON(item.GetMetadataJson())
	return emojiPackDTO{
		AppCode:      item.GetAppCode(),
		ResourceID:   item.GetResourceId(),
		ResourceCode: item.GetResourceCode(),
		Name:         item.GetName(),
		Status:       item.GetStatus(),
		Category:     metadata.Category,
		PricingType:  metadata.PricingType,
		CoverURL:     firstNonEmpty(item.GetPreviewUrl(), item.GetAssetUrl()),
		AnimationURL: item.GetAnimationUrl(),
		RegionIDs:    metadata.RegionIDs,
		SortOrder:    item.GetSortOrder(),
		CreatedAtMS:  item.GetCreatedAtMs(),
		UpdatedAtMS:  item.GetUpdatedAtMs(),
	}
}

func regionIDsFromMetadata(metadataJSON string) []int64 {
	return emojiPackMetadataFromJSON(metadataJSON).RegionIDs
}

func firstNonEmpty(values ...string) string {
	for _, value := range values {
		if value != "" {
			return value
		}
	}
	return ""
}

func grantFromProto(grant *walletv1.ResourceGrant) grantDTO {
	if grant == nil {
		return grantDTO{}
	}
	items := make([]grantItemDTO, 0, len(grant.GetItems()))
	for _, item := range grant.GetItems() {
		var snapshot resourceNoticeSnapshot
		_ = json.Unmarshal([]byte(item.GetResourceSnapshotJson()), &snapshot)
		coverURL := strings.TrimSpace(snapshot.PreviewURL)
		if coverURL == "" {
			coverURL = strings.TrimSpace(snapshot.AssetURL)
		}
		items = append(items, grantItemDTO{
			GrantItemID:          item.GetGrantItemId(),
			GrantID:              item.GetGrantId(),
			ResourceID:           item.GetResourceId(),
			ResourceSnapshotJSON: item.GetResourceSnapshotJson(),
			ResourceCoverURL:     coverURL,
			Quantity:             item.GetQuantity(),
			DurationMS:           item.GetDurationMs(),
			ResultType:           item.GetResultType(),
			WalletTransactionID:  item.GetWalletTransactionId(),
			EntitlementID:        item.GetEntitlementId(),
			CreatedAtMS:          item.GetCreatedAtMs(),
		})
	}
	return grantDTO{
		AppCode:          grant.GetAppCode(),
		GrantID:          grant.GetGrantId(),
		CommandID:        grant.GetCommandId(),
		TargetUserID:     grant.GetTargetUserId(),
		GrantSource:      grant.GetGrantSource(),
		GrantSubjectType: grant.GetGrantSubjectType(),
		GrantSubjectID:   grant.GetGrantSubjectId(),
		Status:           grant.GetStatus(),
		Reason:           grant.GetReason(),
		OperatorUserID:   grant.GetOperatorUserId(),
		RevokedAtMS:      grant.GetRevokedAtMs(),
		RevokedByUserID:  grant.GetRevokedByUserId(),
		RevokeReason:     grant.GetRevokeReason(),
		Items:            items,
		CreatedAtMS:      grant.GetCreatedAtMs(),
		UpdatedAtMS:      grant.GetUpdatedAtMs(),
	}
}
