package app

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

	"hyapp/pkg/appcode"
	"hyapp/pkg/rocketmqx"
	"hyapp/pkg/usermq"
	"hyapp/pkg/xerr"
	"hyapp/services/activity-service/internal/config"
	messageservice "hyapp/services/activity-service/internal/service/message"
)

const userOutboxEventAgencyHostRemoved = "AgencyHostRemoved"

type agencyHostRemovedUserSnapshot struct {
	UserID        int64  `json:"user_id"`
	DisplayUserID string `json:"display_user_id"`
	Username      string `json:"username"`
}

type agencyHostRemovedEvent struct {
	AppCode      string
	EventID      string
	MembershipID int64
	AgencyID     int64
	HostUserID   int64
	Operator     agencyHostRemovedUserSnapshot
	RemovedAtMS  int64
}

func newAgencyHostRemovedNoticeUserOutboxConsumer(cfg config.Config, services *serviceBundle) (*rocketmqx.Consumer, error) {
	consumer, err := rocketmqx.NewConsumer(userOutboxAgencyHostRemovedNoticeConsumerConfig(cfg.RocketMQ))
	if err != nil {
		return nil, err
	}
	if err := consumer.Subscribe(cfg.RocketMQ.UserOutbox.Topic, usermq.TagUserOutboxEvent, func(ctx context.Context, message rocketmqx.ConsumedMessage) error {
		event, ok, err := agencyHostRemovedEventFromUserMessage(message.Body)
		if err != nil || !ok {
			return err
		}
		return createAgencyHostRemovedSystemNotice(appcode.WithContext(ctx, event.AppCode), services.message, event)
	}); err != nil {
		_ = consumer.Shutdown()
		return nil, err
	}
	return consumer, nil
}

func agencyHostRemovedEventFromUserMessage(body []byte) (agencyHostRemovedEvent, bool, error) {
	message, err := usermq.DecodeUserOutboxMessage(body)
	if err != nil {
		return agencyHostRemovedEvent{}, false, err
	}
	if message.EventType != userOutboxEventAgencyHostRemoved {
		return agencyHostRemovedEvent{}, false, nil
	}
	var payload struct {
		MembershipID int64                         `json:"membership_id"`
		AgencyID     int64                         `json:"agency_id"`
		HostUserID   int64                         `json:"host_user_id"`
		Operator     agencyHostRemovedUserSnapshot `json:"operator"`
		RemovedAtMS  int64                         `json:"removed_at_ms"`
	}
	if err := json.Unmarshal([]byte(message.PayloadJSON), &payload); err != nil {
		// 目标事件损坏必须交回 MQ 重试并告警；确认消息会永久丢失主播可见的移除事实。
		return agencyHostRemovedEvent{}, true, err
	}
	payload.Operator.DisplayUserID = strings.TrimSpace(payload.Operator.DisplayUserID)
	payload.Operator.Username = strings.TrimSpace(payload.Operator.Username)
	if payload.MembershipID <= 0 || payload.AgencyID <= 0 || payload.HostUserID <= 0 ||
		payload.Operator.UserID <= 0 || payload.Operator.DisplayUserID == "" || payload.RemovedAtMS <= 0 ||
		message.AggregateType != "agency_membership" || message.AggregateID != payload.MembershipID {
		return agencyHostRemovedEvent{}, true, xerr.New(xerr.InvalidArgument, "agency host removed event is invalid")
	}
	return agencyHostRemovedEvent{
		AppCode:      appcode.Normalize(message.AppCode),
		EventID:      message.EventID,
		MembershipID: payload.MembershipID,
		AgencyID:     payload.AgencyID,
		HostUserID:   payload.HostUserID,
		Operator:     payload.Operator,
		RemovedAtMS:  payload.RemovedAtMS,
	}, true, nil
}

func createAgencyHostRemovedSystemNotice(ctx context.Context, service *messageservice.Service, event agencyHostRemovedEvent) error {
	if service == nil {
		return xerr.New(xerr.Unavailable, "message service is not configured")
	}
	// 昵称为空时只展示短号，避免形成双空格；正常资料同时展示“当前靓号/短 ID + 昵称”。
	operatorLabel := strings.Join(nonEmptyStrings(event.Operator.DisplayUserID, event.Operator.Username), " ")
	content := fmt.Sprintf("你已被 %s agency移除", operatorLabel)
	_, err := service.CreateSystemNotice(ctx, messageservice.NoticeCommand{
		TargetUserID:      event.HostUserID,
		Producer:          "user-service",
		ProducerEventID:   event.EventID,
		ProducerEventType: userOutboxEventAgencyHostRemoved,
		AggregateType:     "agency_membership",
		AggregateID:       strconv.FormatInt(event.MembershipID, 10),
		TemplateID:        "agency_host_removed",
		TemplateVersion:   "v1",
		Title:             "Agency移除通知",
		Summary:           content,
		Body:              content,
		Priority:          50,
		SentAtMS:          event.RemovedAtMS,
		Metadata: map[string]any{
			"agency_id":                event.AgencyID,
			"membership_id":            event.MembershipID,
			"operator_user_id":         event.Operator.UserID,
			"operator_display_user_id": event.Operator.DisplayUserID,
			"operator_username":        event.Operator.Username,
			"removed_at_ms":            event.RemovedAtMS,
		},
	})
	return err
}

func nonEmptyStrings(values ...string) []string {
	items := make([]string, 0, len(values))
	for _, value := range values {
		if value = strings.TrimSpace(value); value != "" {
			items = append(items, value)
		}
	}
	return items
}
