package gamemanagement

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

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

const (
	robotResourceDurationDays = 9999
	robotResourceDurationMS   = int64(robotResourceDurationDays) * int64(24*time.Hour/time.Millisecond)
	robotMinDisplayLevel      = 5
	robotMaxDisplayLevel      = 30
	robotMaxAvatarFrameCoins  = 2_000_000
)

var excludedRobotAvatarFrameResourceIDs = map[int64]struct{}{
	165: {},
	175: {},
}

type robotAppearanceCatalog struct {
	avatarFrames []*walletv1.Resource
	vehicles     []*walletv1.Resource
	longBadges   []*walletv1.Resource
	shortBadges  []*walletv1.Resource
}

func (h *Handler) initializeGeneratedRobotAppearance(ctx context.Context, requestID string, appCode string, actorUserID int64, userID int64) error {
	if h.wallet == nil || h.activity == nil {
		return fmt.Errorf("机器人装扮初始化依赖未配置")
	}
	catalog, err := h.loadRobotAppearanceCatalog(ctx, requestID, appCode)
	if err != nil {
		return err
	}
	avatarFrame := randomRobotResource(catalog.avatarFrames)
	vehicle := randomRobotResource(catalog.vehicles)
	longBadge := randomRobotResource(catalog.longBadges)
	shortBadge := randomRobotResource(catalog.shortBadges)
	if avatarFrame == nil || vehicle == nil || longBadge == nil || shortBadge == nil {
		return fmt.Errorf("机器人装扮资源库不完整: 头像框=%d 座驾=%d 长徽章=%d 短徽章=%d", len(catalog.avatarFrames), len(catalog.vehicles), len(catalog.longBadges), len(catalog.shortBadges))
	}
	if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "avatar_frame", avatarFrame.GetResourceId(), true); err != nil {
		return err
	}
	if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "vehicle", vehicle.GetResourceId(), true); err != nil {
		return err
	}
	if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "long_badge", longBadge.GetResourceId(), false); err != nil {
		return err
	}
	if err := h.grantAndEquipRobotResource(ctx, requestID, appCode, actorUserID, userID, "short_badge", shortBadge.GetResourceId(), false); err != nil {
		return err
	}
	// 财富和魅力等级由 activity-service 按等级规则写入账户、展示投影和等级奖励 job；
	// admin-server 只给出目标等级，避免绕过成长系统直接伪造资料卡字段。
	if err := h.setRobotDisplayLevel(ctx, requestID, appCode, actorUserID, userID, "wealth", int32(robotMinDisplayLevel+randomRobotInt(robotMaxDisplayLevel-robotMinDisplayLevel+1))); err != nil {
		return err
	}
	if err := h.setRobotDisplayLevel(ctx, requestID, appCode, actorUserID, userID, "charm", int32(robotMinDisplayLevel+randomRobotInt(robotMaxDisplayLevel-robotMinDisplayLevel+1))); err != nil {
		return err
	}
	return nil
}

func (h *Handler) loadRobotAppearanceCatalog(ctx context.Context, requestID string, appCode string) (robotAppearanceCatalog, error) {
	avatarFrames, err := h.listRobotResources(ctx, requestID, appCode, "avatar_frame")
	if err != nil {
		return robotAppearanceCatalog{}, err
	}
	vehicles, err := h.listRobotResources(ctx, requestID, appCode, "vehicle")
	if err != nil {
		return robotAppearanceCatalog{}, err
	}
	badges, err := h.listRobotResources(ctx, requestID, appCode, "badge")
	if err != nil {
		return robotAppearanceCatalog{}, err
	}
	catalog := robotAppearanceCatalog{avatarFrames: avatarFrames, vehicles: vehicles}
	for _, badge := range badges {
		if !isRobotVIPBadgeResource(badge) {
			// 机器人批量账号只使用 VIP 体系徽章；普通活动、成就和运营徽章仍留给真实用户或明确活动链路，
			// 避免机器人大量占用非 VIP 资源造成客户端误判身份来源。
			continue
		}
		switch robotBadgeForm(badge.GetMetadataJson()) {
		case "strip", "long":
			catalog.longBadges = append(catalog.longBadges, badge)
		case "tile", "short":
			catalog.shortBadges = append(catalog.shortBadges, badge)
		}
	}
	return catalog, nil
}

func (h *Handler) listRobotResources(ctx context.Context, requestID string, appCode string, resourceType string) ([]*walletv1.Resource, error) {
	resp, err := h.wallet.ListResources(ctx, &walletv1.ListResourcesRequest{
		RequestId:    requestID,
		AppCode:      appCode,
		ResourceType: resourceType,
		Page:         1,
		PageSize:     500,
		ActiveOnly:   true,
	})
	if err != nil {
		return nil, fmt.Errorf("读取机器人%s资源失败: %w", resourceType, err)
	}
	resources := make([]*walletv1.Resource, 0, len(resp.GetResources()))
	for _, item := range resp.GetResources() {
		if item == nil || item.GetResourceId() <= 0 || item.GetStatus() != "active" {
			continue
		}
		if isExcludedRobotAppearanceResource(resourceType, item.GetResourceId()) {
			// 机器人装扮随机池只过滤明确不适合机器人批量露出的资源；资源仍保留在 wallet owner 中，
			// 真人发放、商城和其他后台场景不受这个创建机器人专用策略影响。
			continue
		}
		if resourceType == "avatar_frame" && item.GetCoinPrice() > robotMaxAvatarFrameCoins {
			// 头像框用金币价格做机器人随机池硬边界；价格高于 2000000 的资源通常是稀有或运营保留展示，
			// 创建机器人时不应自动发放，线上批量修复脚本也复用同一条规则。
			continue
		}
		resources = append(resources, item)
	}
	return resources, nil
}

func isExcludedRobotAppearanceResource(resourceType string, resourceID int64) bool {
	if resourceType != "avatar_frame" {
		return false
	}
	_, excluded := excludedRobotAvatarFrameResourceIDs[resourceID]
	return excluded
}

func isRobotVIPBadgeResource(resource *walletv1.Resource) bool {
	if resource == nil || resource.GetResourceType() != "badge" {
		return false
	}
	code := strings.ToLower(strings.TrimSpace(resource.GetResourceCode()))
	name := strings.ToLower(strings.TrimSpace(resource.GetName()))
	return strings.HasPrefix(code, "vip") || strings.HasPrefix(name, "vip")
}

func (h *Handler) grantAndEquipRobotResource(ctx context.Context, requestID string, appCode string, actorUserID int64, userID int64, slot string, resourceID int64, equip bool) error {
	grant, err := h.wallet.GrantResource(ctx, &walletv1.GrantResourceRequest{
		CommandId:      fmt.Sprintf("game_robot_init:%s:%d:%s:%d", requestID, userID, slot, resourceID),
		AppCode:        appCode,
		TargetUserId:   userID,
		ResourceId:     resourceID,
		Quantity:       1,
		DurationMs:     robotResourceDurationMS,
		Reason:         "game_robot_init",
		OperatorUserId: actorUserID,
		GrantSource:    "game_robot_init",
	})
	if err != nil {
		return fmt.Errorf("发放机器人%s失败: %w", slot, err)
	}
	if !equip {
		return nil
	}
	entitlementID := ""
	for _, item := range grant.GetGrant().GetItems() {
		if item.GetResourceId() == resourceID {
			entitlementID = item.GetEntitlementId()
			break
		}
	}
	if _, err := h.wallet.EquipUserResource(ctx, &walletv1.EquipUserResourceRequest{
		RequestId:     fmt.Sprintf("%s:%s:equip", requestID, slot),
		AppCode:       appCode,
		UserId:        userID,
		ResourceId:    resourceID,
		EntitlementId: entitlementID,
	}); err != nil {
		return fmt.Errorf("装备机器人%s失败: %w", slot, err)
	}
	return nil
}

func (h *Handler) setRobotDisplayLevel(ctx context.Context, requestID string, appCode string, actorUserID int64, userID int64, track string, level int32) error {
	_, err := h.activity.SetUserLevel(ctx, &activityv1.SetUserLevelRequest{
		Meta:           activityRequestMeta(requestID, appCode),
		CommandId:      fmt.Sprintf("game_robot_init:%s:%d:%s:%d", requestID, userID, track, level),
		UserId:         userID,
		Track:          track,
		Level:          level,
		OperatorUserId: actorUserID,
		Reason:         "game_robot_init",
	})
	if err != nil {
		return fmt.Errorf("设置机器人%s等级失败: %w", track, err)
	}
	return nil
}

func robotBadgeForm(metadataJSON string) string {
	var payload map[string]any
	if err := json.Unmarshal([]byte(strings.TrimSpace(metadataJSON)), &payload); err != nil {
		return ""
	}
	value, _ := payload["badge_form"].(string)
	return strings.ToLower(strings.TrimSpace(value))
}

func randomRobotResource(items []*walletv1.Resource) *walletv1.Resource {
	if len(items) == 0 {
		return nil
	}
	return items[randomRobotInt(int64(len(items)))]
}

func activityRequestMeta(requestID string, appCode string) *activityv1.RequestMeta {
	return &activityv1.RequestMeta{
		RequestId: requestID,
		Caller:    "admin-server",
		SentAtMs:  time.Now().UnixMilli(),
		AppCode:   appCode,
	}
}
