package connections

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"code.justin.tv/common/twitchhttp"

	"golang.org/x/net/context"
)

// YoutubeUser specifies the fields of a Youtube user
type YoutubeUser struct {
	TwitchID     string    `json:"twitch_id"`
	YoutubeID    string    `json:"youtube_id"`
	Token        string    `json:"token"`
	RefreshToken string    `json:"refresh_token"`
	ExpiresOn    int64     `json:"expires_on"`
	CreatedOn    time.Time `json:"created_on"`
	UpdatedOn    time.Time `json:"updated_on"`
}

// YoutubeResponse is the response object returned by the server
type YoutubeResponse struct {
	Platform    string        `json:"platform"`
	Connections []YoutubeUser `json:"connections"`
}

// AuthYoutube initiates the OAuth2 flow for connecting a Youtube account
func (c *client) AuthYoutube(ctx context.Context, uid string, opts *twitchhttp.ReqOpts) (string, error) {
	path := fmt.Sprintf("/%s/%s/platforms/youtube/auth", ver, uid)
	res, err := c.do(ctx, "GET", path, "authYoutube", opts)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		return "", decodeError(res)
	}

	var resp RedirectPathResp
	err = json.NewDecoder(res.Body).Decode(&resp)
	if err != nil {
		return "", ErrUnexpectedResponse
	}

	return resp.Path, nil
}

// GetYoutubeUser retrieves a YoutubeUser given a user ID
func (c *client) GetYoutubeUser(ctx context.Context, uid string, opts *twitchhttp.ReqOpts) (*YoutubeUser, error) {
	path := fmt.Sprintf("/%s/%s/platforms/youtube", ver, uid)
	res, err := c.do(ctx, "GET", path, "getYoutubeUser", opts)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	switch res.StatusCode {
	case http.StatusOK:
		var data YoutubeResponse
		err = json.NewDecoder(res.Body).Decode(&data)
		if err != nil {
			return nil, err
		}

		return &data.Connections[0], nil
	case http.StatusNotFound:
		return nil, ErrNoConnection
	default:
		return nil, decodeError(res)
	}

}

// CallbackYoutube creates a new Youtube connection given a user ID and query
// parameters from the OAuth2 callback. Requires an authorization token.
func (c *client) CallbackYoutube(ctx context.Context, uid string, val url.Values, opts *twitchhttp.ReqOpts) error {
	path := fmt.Sprintf("/%s/%s/platforms/youtube/callback?%s", ver, uid, val.Encode())
	res, err := c.do(ctx, "GET", path, "postYoutubeUser", opts)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusCreated {
		return decodeError(res)
	}

	return nil
}

// DeleteYoutube deletes a Youtube connection given a user ID. Requires an
// authorization token.
func (c *client) DeleteYoutubeUser(ctx context.Context, uid string, opts *twitchhttp.ReqOpts) error {
	path := fmt.Sprintf("/%s/%s/platforms/youtube", ver, uid)
	res, err := c.do(ctx, "DELETE", path, "deleteYoutubeUser", opts)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusNoContent {
		return decodeError(res)
	}

	return nil
}
