package robot

import (
	"context"
	"strings"

	"cyberstrike-ai/internal/config"

	"github.com/bwmarrin/discordgo"
	"go.uber.org/zap"
)

const (
	discordPlatform        = "discord"
	discordMaxMessageRunes = 2000
)

// StartDiscord 启动 Discord Gateway（WebSocket，无需公网回调）。
func StartDiscord(ctx context.Context, robotsCfg config.RobotsConfig, h MessageHandler, logger *zap.Logger) {
	cfg := robotsCfg.Discord
	if !cfg.Enabled || strings.TrimSpace(cfg.BotToken) == "" {
		return
	}
	go runDiscordLoop(ctx, cfg, h, logger)
}

func runDiscordLoop(ctx context.Context, cfg config.RobotDiscordConfig, h MessageHandler, logger *zap.Logger) {
	backoff := reconnectInitial
	for {
		err := runDiscordSession(ctx, cfg, h, logger)
		if ctx.Err() != nil {
			logger.Info("Discord Gateway 已按配置关闭")
			return
		}
		if err != nil {
			logger.Warn("Discord Gateway 异常，将自动重连", zap.Error(err), zap.Duration("retry_after", backoff))
		}
		if !waitReconnect(ctx, &backoff) {
			return
		}
	}
}

func runDiscordSession(ctx context.Context, cfg config.RobotDiscordConfig, h MessageHandler, logger *zap.Logger) error {
	token := strings.TrimSpace(cfg.BotToken)
	if !strings.HasPrefix(token, "Bot ") {
		token = "Bot " + token
	}
	session, err := discordgo.New(token)
	if err != nil {
		return err
	}
	session.Identify.Intents = discordgo.IntentsGuildMessages |
		discordgo.IntentsDirectMessages |
		discordgo.IntentMessageContent

	session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
		if m == nil || m.Author == nil || m.Author.Bot {
			return
		}
		text := strings.TrimSpace(m.Content)
		if text == "" {
			return
		}
		if m.GuildID != "" {
			if !cfg.AllowGuildMessages {
				return
			}
			if s.State.User == nil || !discordMentionsBot(m, s.State.User.ID) {
				return
			}
		}
		userID := discordSessionKey(m.GuildID, m.Author.ID)
		logger.Info("Discord 收到消息", zap.String("from", userID), zap.String("content", text))
		reply := h.HandleMessage(discordPlatform, userID, text)
		discordPostReply(s, m.ChannelID, reply, logger)
	})

	if err := session.Open(); err != nil {
		return err
	}
	logger.Info("Discord Gateway 已连接，等待收消息")
	defer session.Close()

	<-ctx.Done()
	return ctx.Err()
}

func discordMentionsBot(m *discordgo.MessageCreate, botUserID string) bool {
	if m == nil || botUserID == "" {
		return false
	}
	for _, mention := range m.Mentions {
		if mention != nil && mention.ID == botUserID {
			return true
		}
	}
	return strings.Contains(m.Content, "<@"+botUserID+">") || strings.Contains(m.Content, "<@!"+botUserID+">")
}

func discordSessionKey(guildID, userID string) string {
	guildID = strings.TrimSpace(guildID)
	userID = strings.TrimSpace(userID)
	if guildID == "" {
		return "u:" + userID
	}
	return "g:" + guildID + "|u:" + userID
}

func discordPostReply(s *discordgo.Session, channelID, reply string, logger *zap.Logger) {
	reply = trimReply(reply)
	if reply == "" {
		return
	}
	for _, chunk := range splitTextChunks(reply, discordMaxMessageRunes) {
		if _, err := s.ChannelMessageSend(channelID, chunk); err != nil {
			logger.Warn("Discord 发送回复失败", zap.String("channel", channelID), zap.Error(err))
			return
		}
	}
}
