package resource

import (
	"strings"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/middleware"
	walletv1 "hyapp.local/api/proto/wallet/v1"

	"github.com/gin-gonic/gin"
)

const dayMillis int64 = 24 * 60 * 60 * 1000

type resourceRequest struct {
	ResourceCode        string `json:"resourceCode"`
	ResourceType        string `json:"resourceType"`
	Name                string `json:"name"`
	Status              string `json:"status"`
	Amount              int64  `json:"amount"`
	ManagerGrantEnabled *bool  `json:"managerGrantEnabled"`
	AssetURL            string `json:"assetUrl"`
	PreviewURL          string `json:"previewUrl"`
	SortOrder           int32  `json:"sortOrder"`
}

type resourceGroupRequest struct {
	GroupCode   string                     `json:"groupCode"`
	Name        string                     `json:"name"`
	Status      string                     `json:"status"`
	Description string                     `json:"description"`
	SortOrder   int32                      `json:"sortOrder"`
	Items       []resourceGroupItemRequest `json:"items"`
}

type resourceGroupItemRequest struct {
	ItemType     string `json:"itemType"`
	ResourceID   int64  `json:"resourceId"`
	AssetType    string `json:"assetType"`
	Amount       int64  `json:"amount"`
	DurationDays int64  `json:"durationDays"`
	SortOrder    int32  `json:"sortOrder"`
}

type giftRequest struct {
	GiftID           string   `json:"giftId"`
	ResourceID       int64    `json:"resourceId"`
	Status           string   `json:"status"`
	Name             string   `json:"name"`
	SortOrder        int32    `json:"sortOrder"`
	PresentationJSON string   `json:"presentationJson"`
	PriceVersion     string   `json:"priceVersion"`
	GiftTypeCode     string   `json:"giftTypeCode"`
	ChargeAssetType  string   `json:"chargeAssetType"`
	CoinPrice        int64    `json:"coinPrice"`
	GiftPointAmount  int64    `json:"giftPointAmount"`
	HeatValue        int64    `json:"heatValue"`
	EffectiveAtMS    int64    `json:"effectiveAtMs"`
	EffectiveFromMS  int64    `json:"effectiveFromMs"`
	EffectiveToMS    int64    `json:"effectiveToMs"`
	EffectTypes      []string `json:"effectTypes"`
	RegionIDs        []int64  `json:"regionIds"`
}

type grantResourceRequest struct {
	CommandID    string `json:"commandId"`
	TargetUserID int64  `json:"targetUserId"`
	ResourceID   int64  `json:"resourceId"`
	Quantity     int64  `json:"quantity"`
	DurationMS   int64  `json:"durationMs"`
	Reason       string `json:"reason"`
}

type grantGroupRequest struct {
	CommandID    string `json:"commandId"`
	TargetUserID int64  `json:"targetUserId"`
	GroupID      int64  `json:"groupId"`
	Reason       string `json:"reason"`
}

func (r resourceRequest) createProto(c *gin.Context) *walletv1.CreateResourceRequest {
	resourceType := normalizeResourceType(r.ResourceType)
	walletAssetType, walletAssetAmount := resourceWalletAsset(resourceType, r.Amount)
	return &walletv1.CreateResourceRequest{
		RequestId:           middleware.CurrentRequestID(c),
		AppCode:             appctx.FromContext(c.Request.Context()),
		ResourceCode:        strings.TrimSpace(r.ResourceCode),
		ResourceType:        resourceType,
		Name:                strings.TrimSpace(r.Name),
		Status:              strings.TrimSpace(r.Status),
		Grantable:           true,
		ManagerGrantEnabled: managerGrantEnabledOrDefault(r.ManagerGrantEnabled),
		GrantStrategy:       resourceGrantStrategy(resourceType),
		WalletAssetType:     walletAssetType,
		WalletAssetAmount:   walletAssetAmount,
		UsageScopes:         []string{resourceType},
		AssetUrl:            strings.TrimSpace(r.AssetURL),
		PreviewUrl:          strings.TrimSpace(r.PreviewURL),
		AnimationUrl:        "",
		MetadataJson:        "{}",
		SortOrder:           r.SortOrder,
		OperatorUserId:      actorID(c),
	}
}

func (r resourceRequest) updateProto(c *gin.Context, resourceID int64) *walletv1.UpdateResourceRequest {
	resourceType := normalizeResourceType(r.ResourceType)
	walletAssetType, walletAssetAmount := resourceWalletAsset(resourceType, r.Amount)
	return &walletv1.UpdateResourceRequest{
		RequestId:           middleware.CurrentRequestID(c),
		AppCode:             appctx.FromContext(c.Request.Context()),
		ResourceId:          resourceID,
		ResourceCode:        strings.TrimSpace(r.ResourceCode),
		ResourceType:        resourceType,
		Name:                strings.TrimSpace(r.Name),
		Status:              strings.TrimSpace(r.Status),
		Grantable:           true,
		ManagerGrantEnabled: managerGrantEnabledOrDefault(r.ManagerGrantEnabled),
		GrantStrategy:       resourceGrantStrategy(resourceType),
		WalletAssetType:     walletAssetType,
		WalletAssetAmount:   walletAssetAmount,
		UsageScopes:         []string{resourceType},
		AssetUrl:            strings.TrimSpace(r.AssetURL),
		PreviewUrl:          strings.TrimSpace(r.PreviewURL),
		AnimationUrl:        "",
		MetadataJson:        "{}",
		SortOrder:           r.SortOrder,
		OperatorUserId:      actorID(c),
	}
}

func (r resourceGroupRequest) createProto(c *gin.Context) *walletv1.CreateResourceGroupRequest {
	return &walletv1.CreateResourceGroupRequest{
		RequestId:      middleware.CurrentRequestID(c),
		AppCode:        appctx.FromContext(c.Request.Context()),
		GroupCode:      strings.TrimSpace(r.GroupCode),
		Name:           strings.TrimSpace(r.Name),
		Status:         strings.TrimSpace(r.Status),
		Description:    strings.TrimSpace(r.Description),
		SortOrder:      r.SortOrder,
		Items:          groupItemInputs(r.Items),
		OperatorUserId: actorID(c),
	}
}

func (r resourceGroupRequest) updateProto(c *gin.Context, groupID int64) *walletv1.UpdateResourceGroupRequest {
	return &walletv1.UpdateResourceGroupRequest{
		RequestId:      middleware.CurrentRequestID(c),
		AppCode:        appctx.FromContext(c.Request.Context()),
		GroupId:        groupID,
		GroupCode:      strings.TrimSpace(r.GroupCode),
		Name:           strings.TrimSpace(r.Name),
		Status:         strings.TrimSpace(r.Status),
		Description:    strings.TrimSpace(r.Description),
		SortOrder:      r.SortOrder,
		Items:          groupItemInputs(r.Items),
		OperatorUserId: actorID(c),
	}
}

func (r giftRequest) createProto(c *gin.Context) *walletv1.CreateGiftConfigRequest {
	return &walletv1.CreateGiftConfigRequest{
		RequestId:        middleware.CurrentRequestID(c),
		AppCode:          appctx.FromContext(c.Request.Context()),
		GiftId:           strings.TrimSpace(r.GiftID),
		ResourceId:       r.ResourceID,
		Status:           strings.TrimSpace(r.Status),
		Name:             strings.TrimSpace(r.Name),
		SortOrder:        r.SortOrder,
		PresentationJson: strings.TrimSpace(r.PresentationJSON),
		PriceVersion:     strings.TrimSpace(r.PriceVersion),
		GiftTypeCode:     strings.TrimSpace(r.GiftTypeCode),
		ChargeAssetType:  strings.TrimSpace(r.ChargeAssetType),
		CoinPrice:        r.CoinPrice,
		GiftPointAmount:  r.GiftPointAmount,
		HeatValue:        r.HeatValue,
		EffectiveAtMs:    r.EffectiveAtMS,
		EffectiveFromMs:  r.EffectiveFromMS,
		EffectiveToMs:    r.EffectiveToMS,
		EffectTypes:      r.EffectTypes,
		OperatorUserId:   actorID(c),
		RegionIds:        r.RegionIDs,
	}
}

func (r giftRequest) updateProto(c *gin.Context, giftID string) *walletv1.UpdateGiftConfigRequest {
	return &walletv1.UpdateGiftConfigRequest{
		RequestId:        middleware.CurrentRequestID(c),
		AppCode:          appctx.FromContext(c.Request.Context()),
		GiftId:           strings.TrimSpace(giftID),
		ResourceId:       r.ResourceID,
		Status:           strings.TrimSpace(r.Status),
		Name:             strings.TrimSpace(r.Name),
		SortOrder:        r.SortOrder,
		PresentationJson: strings.TrimSpace(r.PresentationJSON),
		PriceVersion:     strings.TrimSpace(r.PriceVersion),
		GiftTypeCode:     strings.TrimSpace(r.GiftTypeCode),
		ChargeAssetType:  strings.TrimSpace(r.ChargeAssetType),
		CoinPrice:        r.CoinPrice,
		GiftPointAmount:  r.GiftPointAmount,
		HeatValue:        r.HeatValue,
		EffectiveAtMs:    r.EffectiveAtMS,
		EffectiveFromMs:  r.EffectiveFromMS,
		EffectiveToMs:    r.EffectiveToMS,
		EffectTypes:      r.EffectTypes,
		OperatorUserId:   actorID(c),
		RegionIds:        r.RegionIDs,
	}
}

func managerGrantEnabledOrDefault(value *bool) *bool {
	enabled := true
	if value != nil {
		enabled = *value
	}
	return &enabled
}

func groupItemInputs(items []resourceGroupItemRequest) []*walletv1.ResourceGroupItemInput {
	out := make([]*walletv1.ResourceGroupItemInput, 0, len(items))
	for _, item := range items {
		itemType := strings.ToLower(strings.TrimSpace(item.ItemType))
		if itemType == "wallet_asset" {
			out = append(out, &walletv1.ResourceGroupItemInput{
				ItemType:          itemType,
				WalletAssetType:   strings.TrimSpace(item.AssetType),
				WalletAssetAmount: item.Amount,
				Quantity:          1,
				SortOrder:         item.SortOrder,
			})
			continue
		}
		out = append(out, &walletv1.ResourceGroupItemInput{
			ItemType:   "resource",
			ResourceId: item.ResourceID,
			Quantity:   1,
			DurationMs: item.DurationDays * dayMillis,
			SortOrder:  item.SortOrder,
		})
	}
	return out
}

func normalizeResourceType(value string) string {
	return strings.ToLower(strings.TrimSpace(value))
}

func resourceWalletAsset(resourceType string, amount int64) (string, int64) {
	if resourceType == "coin" {
		return "COIN", amount
	}
	return "", 0
}

func resourceGrantStrategy(resourceType string) string {
	switch resourceType {
	case "coin":
		return "wallet_credit"
	case "avatar_frame", "profile_card", "vehicle", "chat_bubble":
		return "extend_expiry"
	case "badge":
		return "set_active_flag"
	default:
		return "increase_quantity"
	}
}
