package twitch

import (
	"fmt"
	"github.com/cenkalti/backoff/v4"
	"github.com/rs/zerolog/log"
	"github.com/velour/catbase/bot"
	"github.com/velour/catbase/connectors/discord"
	"strings"
)

func (t *Twitch) mkBridge(r bot.Request) bool {
	ircCh := "#" + r.Values["twitchChannel"]
	if err := t.startConn(); err != nil {
		t.b.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("Could not connect to IRC: %s", err))
	}
	t.irc.Join(ircCh)
	t.bridgeMap[r.Msg.Channel] = ircCh
	t.b.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("This post is tracking %s", ircCh))
	return true
}

func (t *Twitch) rmBridge(r bot.Request) bool {
	ch, ok := t.bridgeMap[r.Msg.Channel]
	if ok {
		delete(t.bridgeMap, r.Msg.Channel)
		t.b.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("No longer tracking %s.", ch))
		return true
	}
	t.b.Send(r.Conn, bot.Message, r.Msg.Channel, "This is not a connected bridge channel.")
	return true
}

func (t *Twitch) bridgeMsg(r bot.Request) bool {
	if ircCh := t.bridgeMap[r.Msg.Channel]; ircCh != "" {
		if t.irc == nil {
			if err := t.startConn(); err != nil {
				t.b.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("Could not connect to IRC: %s", err))
			}
			t.irc.Join(ircCh)
		}
		replaceSet := t.c.Get("twitch.replaceset", "\"'-")
		who := r.Msg.User.Name
		for _, c := range replaceSet {
			who = strings.ReplaceAll(who, string(c), "")
		}
		who = strings.Split(who, " ")[0][:9]
		msg := fmt.Sprintf("%s: %s", who, r.Msg.Body)
		t.irc.sendMessage(ircCh, msg)
	}
	return false
}

func (t *Twitch) ircMsg(channel, who, body string) {
	for thread, ircCh := range t.bridgeMap {
		if ircCh == channel {
			t.b.Send(t.b.DefaultConnector(), bot.Message, thread, fmt.Sprintf("%s: %s", who, body))
		}
	}
}

func (t *Twitch) startBridgeMsg(threadName, twitchChannel, msg string) error {
	if !strings.HasPrefix(twitchChannel, "#") {
		twitchChannel = "#" + twitchChannel
	}
	if err := t.startConn(); err != nil {
		return err
	}

	chID, err := t.mkForumPost(threadName, msg)
	if err != nil {
		return err
	}
	log.Debug().Msgf("Opened thread %s", chID)

	err = t.irc.Join(twitchChannel)
	if err != nil {
		return err
	}
	t.bridgeMap[chID] = twitchChannel
	return nil
}

func (t *Twitch) startBridge(threadName, twitchChannel string) error {
	if !strings.HasPrefix(twitchChannel, "#") {
		twitchChannel = "#" + twitchChannel
	}
	msg := fmt.Sprintf("This post is tracking %s", twitchChannel)
	return t.startBridgeMsg(threadName, twitchChannel, msg)
}

func (t *Twitch) startConn() error {
	if t.irc == nil {
		err := backoff.Retry(func() error {
			err := t.connect()
			if err != nil {
				log.Error().Err(err).Msg("could not connect to IRC")
				return err
			}
			return nil
		}, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 5))
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *Twitch) connect() error {
	t.ircLock.Lock()
	defer t.ircLock.Unlock()
	twitchServer := t.c.Get("twitch.ircserver", "irc.chat.twitch.tv:6697")
	twitchNick := t.c.Get("twitch.nick", "")
	twitchPass := t.c.Get("twitch.pass", "")
	twitchIRC, err := t.ConnectIRC(twitchServer, twitchNick, twitchPass, t.ircMsg, func() {
		t.ircLock.Lock()
		defer t.ircLock.Unlock()
		t.irc = nil
	})
	if err != nil {
		return err
	}
	t.irc = twitchIRC
	return nil
}

func (t *Twitch) mkForumPost(name, msg string) (string, error) {
	forum := t.c.Get("twitch.forum", "")
	if forum == "" {
		return "", fmt.Errorf("no forum available")
	}
	switch c := t.b.DefaultConnector().(type) {
	case *discord.Discord:
		chID, err := c.CreateRoom(name, msg, forum, t.c.GetInt("twitch.threadduration", 60))
		if err != nil {
			return "", err
		}
		return chID, nil
	default:
		return "", fmt.Errorf("non-Discord connectors not supported")
	}
}