package app

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

	"hyapp/pkg/appcode"
	"hyapp/pkg/walletmq"
	"hyapp/pkg/xerr"
	messagedomain "hyapp/services/activity-service/internal/domain/message"
	messageservice "hyapp/services/activity-service/internal/service/message"
)

const vipDailyCoinRebateAvailableEventType = walletmq.EventTypeVIPDailyCoinRebateAvailable

// vipRebateAvailableEvent 是 wallet outbox 的逐用户返现资格快照。
// activity-service 只把这个已提交事实投影为 inbox；资格、金额、过期和最终入账仍由 wallet owner 判定。
type vipRebateAvailableEvent struct {
	AppCode       string
	EventID       string
	RebateID      string
	UserID        int64
	TaskDay       string
	VIPLevel      int32
	VIPName       string
	CoinAmount    int64
	AvailableAtMS int64
	ExpiresAtMS   int64
	ConfigVersion int64
	CreatedAtMS   int64
}

func vipRebateAvailableEventFromWalletMessage(body []byte) (vipRebateAvailableEvent, bool, error) {
	message, err := walletmq.DecodeWalletOutboxMessage(body)
	if err != nil {
		return vipRebateAvailableEvent{}, false, err
	}
	if message.EventType != vipDailyCoinRebateAvailableEventType {
		return vipRebateAvailableEvent{}, false, nil
	}
	var payload struct {
		RebateID      string `json:"rebate_id"`
		UserID        int64  `json:"user_id"`
		TaskDay       string `json:"task_day"`
		VIPLevel      int32  `json:"vip_level"`
		VIPName       string `json:"vip_name"`
		CoinAmount    int64  `json:"coin_amount"`
		AvailableAtMS int64  `json:"available_at_ms"`
		ExpiresAtMS   int64  `json:"expires_at_ms"`
		ConfigVersion int64  `json:"config_version"`
		CreatedAtMS   int64  `json:"created_at_ms"`
	}
	if err := json.Unmarshal([]byte(message.PayloadJSON), &payload); err != nil {
		// 目标事件 payload 损坏必须让 MQ 重投并进入告警，不能确认后永久丢失用户领取入口。
		return vipRebateAvailableEvent{}, false, err
	}
	payload.RebateID = strings.TrimSpace(payload.RebateID)
	payload.TaskDay = strings.TrimSpace(payload.TaskDay)
	payload.VIPName = strings.TrimSpace(payload.VIPName)
	if payload.CreatedAtMS <= 0 {
		payload.CreatedAtMS = message.OccurredAtMS
	}
	if payload.RebateID == "" || payload.UserID <= 0 || payload.UserID != message.UserID || !validUTCTaskDay(payload.TaskDay) || payload.VIPLevel <= 0 || payload.CoinAmount <= 0 || payload.AvailableAtMS <= 0 || payload.ExpiresAtMS <= payload.AvailableAtMS || payload.ConfigVersion <= 0 {
		return vipRebateAvailableEvent{}, false, xerr.New(xerr.InvalidArgument, "VIP rebate wallet event is invalid")
	}
	return vipRebateAvailableEvent{
		AppCode:       appcode.Normalize(message.AppCode),
		EventID:       message.EventID,
		RebateID:      payload.RebateID,
		UserID:        payload.UserID,
		TaskDay:       payload.TaskDay,
		VIPLevel:      payload.VIPLevel,
		VIPName:       payload.VIPName,
		CoinAmount:    payload.CoinAmount,
		AvailableAtMS: payload.AvailableAtMS,
		ExpiresAtMS:   payload.ExpiresAtMS,
		ConfigVersion: payload.ConfigVersion,
		CreatedAtMS:   payload.CreatedAtMS,
	}, true, nil
}

func createVIPRebateSystemNotice(ctx context.Context, service *messageservice.Service, event vipRebateAvailableEvent) error {
	if service == nil {
		return xerr.New(xerr.Unavailable, "message service is not configured")
	}
	// 返现资格尚未入账，英文文案必须表达“可领取”而不是“已到账”，避免客户端展示与钱包事实冲突。
	title, summary := messageservice.VIPDailyCoinRebateNoticeCopy(event.CoinAmount)
	_, err := service.CreateSystemNotice(ctx, messageservice.NoticeCommand{
		TargetUserID:      event.UserID,
		Producer:          "wallet-service",
		ProducerEventID:   event.EventID,
		ProducerEventType: vipDailyCoinRebateAvailableEventType,
		AggregateType:     "vip_daily_coin_rebate",
		AggregateID:       event.RebateID,
		TemplateID:        messageservice.VIPDailyCoinRebateNoticeTemplateID,
		TemplateVersion:   messageservice.VIPDailyCoinRebateNoticeTemplateVersion,
		Title:             title,
		Summary:           summary,
		Body:              summary,
		Actions:           []messagedomain.InboxAction{messageservice.VIPDailyCoinRebateNoticeAction(event.RebateID)},
		Priority:          50,
		SentAtMS:          event.AvailableAtMS,
		ExpireAtMS:        event.ExpiresAtMS,
		Metadata: map[string]any{
			"rebate_id":       event.RebateID,
			"task_day":        event.TaskDay,
			"vip_level":       event.VIPLevel,
			"vip_name":        event.VIPName,
			"coin_amount":     event.CoinAmount,
			"available_at_ms": event.AvailableAtMS,
			"expires_at_ms":   event.ExpiresAtMS,
			"config_version":  event.ConfigVersion,
			"claim_status":    "claimable",
		},
	})
	return err
}

func validUTCTaskDay(value string) bool {
	parsed, err := time.Parse("2006-01-02", value)
	return err == nil && parsed.Location() == time.UTC && parsed.Format("2006-01-02") == value
}
