package connections

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

	"golang.org/x/net/context"

	"code.justin.tv/common/twitchhttp"
)

// TwitterUser defines the attributes received from Twitter API.
type TwitterUser struct {
	TwitchID          string `json:"twitch_id"`
	TwitterID         string `json:"twitter_id"`
	TwitterScreenName string `json:"twitter_screen_name"`
	AccessToken       string `json:"access_token"`
	AccessSecret      string `json:"access_secret"`

	CreatedOn time.Time `json:"created_on"`
	UpdatedOn time.Time `json:"updated_on"`
}

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

// AuthTwitter gets a Twitter redirect URL
func (c *client) AuthTwitter(ctx context.Context, uid, clientID string, opts *twitchhttp.ReqOpts) (string, error) {
	path := fmt.Sprintf("/%s/%s/platforms/twitter/auth?client_id=%s", ver, uid, clientID)
	res, err := c.do(ctx, "GET", path, "authTwitter", 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
}

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

	switch res.StatusCode {
	case http.StatusOK:
		var data TwitterResponse
		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)
	}

}

// PostTwitterUser creates a new Twitter connection given a user ID, a Twitter
// OAuth token, and a Twitter OAuth verifier. Requires an authorization token.
func (c *client) PostTwitterUser(ctx context.Context, uid, token, verifier, nonce string, opts *twitchhttp.ReqOpts) error {
	path := fmt.Sprintf("/%s/%s/platforms/twitter/callback?oauth_token=%s&oauth_verifier=%s&nonce=%s", ver, uid, token, verifier, nonce)
	res, err := c.do(ctx, "GET", path, "postTwitterUser", opts)
	if err != nil {
		return err
	}
	defer res.Body.Close()

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

	return nil
}

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

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

	return nil
}
