package logic

import (
	"context"
	"fmt"
	"sync"

	"code.justin.tv/creator-collab/log/errors"
	"code.justin.tv/eventbus/schema/pkg/channel_endorsement_list"
	autohosterrors "code.justin.tv/live/autohost/internal/errors"
)

// AddList adds channelIDs to a userID's autohost channel targets
func (T *Impl) AddList(ctx context.Context, callerID, channelID string, userIDsToAdd []string) ([]string, error) {
	// Check callerID authorization
	authorized, err := T.auth.CanEditChannelSettings(ctx, callerID, channelID)
	if err != nil {
		return nil, err
	}
	if !authorized {
		return nil, autohosterrors.Forbidden
	}

	var targetIDs []string
	for _, targetID := range userIDsToAdd {
		if targetID == "" {
			continue
		}
		// Don't allow adding yourself to your autohost list
		if targetID == channelID {
			continue
		}

		targetIDs = append(targetIDs, targetID)
	}

	oldList, err := T.db.GetList(ctx, channelID)
	if err != nil {
		return nil, err
	}

	if len(targetIDs) == 0 {
		return oldList, nil
	}

	addedTargetIDs, _ := listDiff(targetIDs, oldList)
	newList := append(oldList, addedTargetIDs...)
	newList, err = T.db.SetList(ctx, channelID, newList)
	if err != nil {
		return nil, err
	}

	err = T.cache.SetList(ctx, channelID, newList)
	if err != nil {
		T.logger.Error(err)
	}

	wg := sync.WaitGroup{}
	wg.Add(3)

	go func() {
		defer wg.Done()
		if err = T.eventPublisher.ChannelEndorsementListUpdate(ctx, &channel_endorsement_list.ChannelEndorsementListUpdate{UserId: channelID}); err != nil {
			T.logger.Error(errors.Wrap(err, "could not publish channel endorsement list update event", errors.Fields{"channel_id": channelID}))
		}
	}()

	go func() {
		defer wg.Done()
		err := T.setListSNS.SendToTopic(ctx, setListMessage{
			ChannelID: channelID,
			NewList:   newList,
		})
		if err != nil {
			verboseErr := fmt.Errorf("Error sending event (add autohost list) to sns. Error: %s", err)
			T.logger.Error(verboseErr)
		}
	}()

	go func() {
		defer wg.Done()
		err := T.helpers.AddedChannel(ctx, channelID, addedTargetIDs)
		if err != nil {
			T.logger.Error(err)
		}
	}()

	wg.Wait()

	return newList, nil
}
