package autohost

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"strconv"

	"code.justin.tv/foundation/twitchclient"
	"code.justin.tv/live/autohost/lib"
)

// Client contains operations on the Autohost service.
type Client interface {
	GetSettings(ctx context.Context, callerID, userID string, reqOpts *twitchclient.ReqOpts) (*lib.Settings, error)
	UpdateSettings(ctx context.Context, callerID, userID string, settings lib.UpdateSettingsInput, reqOpts *twitchclient.ReqOpts) (*lib.Settings, error)

	HostTarget(ctx context.Context, callerID, channelID, targetID string, reqOpts *twitchclient.ReqOpts) (*lib.Host, error)
	Unhost(ctx context.Context, callerID, channelID string, reqOpts *twitchclient.ReqOpts) (*lib.Unhost, error)
}

type clientImpl struct {
	twitchclient.Client
}

var _ Client = new(clientImpl)

// NewClient returns an object implementing the Client interface
func NewClient(conf twitchclient.ClientConf) (Client, error) {
	if conf.TimingXactName == "" {
		conf.TimingXactName = "autohost"
	}
	twitchClient, err := twitchclient.NewClient(conf)
	return &clientImpl{twitchClient}, err
}

func (c *clientImpl) GetSettings(ctx context.Context, callerID, userID string, reqOpts *twitchclient.ReqOpts) (*lib.Settings, error) {
	params := url.Values{}
	if callerID != "" {
		params.Add(lib.CallerIDKey, callerID)
	}
	u := url.URL{
		Path:     fmt.Sprintf("/settings/%s", userID),
		RawQuery: params.Encode(),
	}

	req, err := c.NewRequest("GET", u.RequestURI(), nil)
	if err != nil {
		return nil, &twitchclient.Error{StatusCode: http.StatusInternalServerError, Message: err.Error()}
	}

	var settings lib.Settings
	_, err = c.DoJSON(ctx, &settings, req, twitchclient.MergeReqOpts(reqOpts, twitchclient.ReqOpts{
		StatName:       "service.autohost.get_settings",
		StatSampleRate: 0.1,
	}))
	return &settings, err
}

func (c *clientImpl) UpdateSettings(ctx context.Context, callerID, userID string, settings lib.UpdateSettingsInput, reqOpts *twitchclient.ReqOpts) (*lib.Settings, error) {
	params := url.Values{}
	if callerID != "" {
		params.Add(lib.CallerIDKey, callerID)
	}
	if settings.Enabled != nil {
		params.Add(lib.EnabledKey, strconv.FormatBool(*settings.Enabled))
	}
	if settings.TeamHost != nil {
		params.Add(lib.TeamHostKey, strconv.FormatBool(*settings.TeamHost))
	}
	if settings.DeprioritizeVodcast != nil {
		params.Add(lib.DeprioritizeVodcastKey, strconv.FormatBool(*settings.DeprioritizeVodcast))
	}
	if settings.Strategy != nil {
		params.Add(lib.StrategyKey, string(*settings.Strategy))
	}

	req, err := c.NewRequest("PUT", fmt.Sprintf("%s?%s", path.Join("settings", userID), params.Encode()), nil)
	if err != nil {
		return nil, &twitchclient.Error{StatusCode: http.StatusInternalServerError, Message: err.Error()}
	}

	var newSettings lib.Settings
	_, err = c.DoJSON(ctx, &newSettings, req, twitchclient.MergeReqOpts(reqOpts, twitchclient.ReqOpts{
		StatName:       "service.autohost.update_settings",
		StatSampleRate: 0.1,
	}))
	return &newSettings, err
}

func (c *clientImpl) HostTarget(ctx context.Context, callerID, channelID, targetID string, reqOpts *twitchclient.ReqOpts) (*lib.Host, error) {
	req, err := c.NewRequest("POST", fmt.Sprintf("host?user_id=%s&channel_id=%s&target_id=%s", callerID, channelID, targetID), nil)
	if err != nil {
		return nil, &twitchclient.Error{StatusCode: http.StatusInternalServerError, Message: err.Error()}
	}

	var host lib.Host
	_, err = c.DoJSON(ctx, &host, req, twitchclient.MergeReqOpts(reqOpts, twitchclient.ReqOpts{
		StatName:       "service.autohost.host",
		StatSampleRate: 0.1,
	}))
	return &host, err
}

func (c *clientImpl) Unhost(ctx context.Context, callerID, channelID string, reqOpts *twitchclient.ReqOpts) (*lib.Unhost, error) {
	req, err := c.NewRequest("DELETE", fmt.Sprintf("host?user_id=%s&channel_id=%s", callerID, channelID), nil)
	if err != nil {
		return nil, &twitchclient.Error{StatusCode: http.StatusInternalServerError, Message: err.Error()}
	}

	var unhost lib.Unhost
	_, err = c.DoJSON(ctx, &unhost, req, twitchclient.MergeReqOpts(reqOpts, twitchclient.ReqOpts{
		StatName:       "service.autohost.unhost",
		StatSampleRate: 0.1,
	}))
	return &unhost, err
}
