package logic

import (
	"code.justin.tv/live/autohost/internal/hosting/redis"

	telemetry "code.justin.tv/amzn/TwitchTelemetry"

	"code.justin.tv/live/autohost/internal/hosting/clients/liveline"

	"code.justin.tv/live/autohost/rpc/hosting"

	"code.justin.tv/live/autohost/internal/hosting/clients/recs"
	"code.justin.tv/live/autohost/internal/hosting/eventbus"

	"code.justin.tv/live/autohost/internal/hosting/pdms"

	"context"

	"code.justin.tv/live/autohost/internal/hosting/auth"
	"code.justin.tv/live/autohost/internal/hosting/memcached"

	"code.justin.tv/creator-collab/log"
	"code.justin.tv/live/autohost/internal/hosting/clients/clue"
	"code.justin.tv/live/autohost/internal/hosting/clients/sns"
	"code.justin.tv/live/autohost/internal/hosting/clients/spade"
	"code.justin.tv/live/autohost/internal/hosting/storage"
	"code.justin.tv/live/autohost/lib"
)

const (
	MaxEndorsedChannels = 50
)

type Logic interface {
	GetSettings(ctx context.Context, callerID, userID string) (*lib.Settings, error)
	UpdateSettings(ctx context.Context, callerID, userID string, settings *lib.UpdateSettingsInput) (*lib.Settings, error)

	GetList(ctx context.Context, user string) ([]string, error)
	SetList(ctx context.Context, callerID, userID string, list []string) ([]string, error)
	AddList(ctx context.Context, callerID, channelID string, userIDsToAdd []string) ([]string, error)
	RemoveList(ctx context.Context, callerID, channelID string, userIDsToRemove []string) ([]string, error)

	HostTarget(ctx context.Context, userID, channelID, targetID string) error
	Unhost(ctx context.Context, userID, channelID string) error

	GetEndorsedChannels(ctx context.Context, userContext *hosting.UserContext, targetChannelID string, limit int) ([]*hosting.EndorsedChannel, error)

	// EventBusHandler callbacks
	OnUserDestroyEventReceived(ctx context.Context, userID string) error
}

type Params struct {
	DB               storage.Storage
	SNSClient        sns.Client
	Auth             auth.Auth
	ClueClient       clue.Client
	SpadeClient      spade.Client
	Memcached        memcached.Cache
	PDMSClient       pdms.Client
	TwitchRecsClient recs.Client
	LivelineClient   liveline.Client
	Logger           log.Logger
	EventPublisher   eventbus.Publisher
	SampleReporter   *telemetry.SampleReporter
	RateLimiter      redis.RateLimiter
}

// New creates a new Logic from a backend.
func New(params *Params) (Logic, error) {
	logicHelpers, err := NewLogicHelpers(params.DB)
	if err != nil {
		return nil, err
	}

	accessLogger := newAccessLogger(params.Logger)

	return &Impl{
		db:      params.DB,
		cache:   params.Memcached,
		pdms:    params.PDMSClient,
		recs:    params.TwitchRecsClient,
		helpers: logicHelpers,

		auth:           params.Auth,
		hostmode:       params.ClueClient,
		tracking:       params.SpadeClient,
		setListSNS:     params.SNSClient,
		eventPublisher: params.EventPublisher,
		liveline:       params.LivelineClient,
		rateLimiter:    params.RateLimiter,

		accessLogger:   accessLogger,
		logger:         params.Logger,
		sampleReporter: params.SampleReporter,
	}, nil
}

type Impl struct {
	accessLogger   *accessLogger
	auth           auth.Auth
	cache          memcached.Cache
	db             storage.Storage
	eventPublisher eventbus.Publisher
	helpers        Helpers
	hostmode       clue.Client
	liveline       liveline.Client
	logger         log.Logger
	pdms           pdms.Client
	rateLimiter    redis.RateLimiter
	recs           recs.Client
	setListSNS     sns.Client
	sampleReporter *telemetry.SampleReporter
	tracking       spade.Client
}

// LogicImpl implements the Logic interface.
var _ Logic = &Impl{}

type setListMessage struct {
	ChannelID string   `json:"channel_id"`
	NewList   []string `json:"new_list"`
}
