package connections

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

	"golang.org/x/net/context"

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

// SteamUser defines the attributes received from Steam API.
type SteamUser struct {
	TwitchID string `json:"twitch_id"`
	SteamID  string `json:"steam_id"`

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

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

// AuthSteam gets a Steam redirect URL
func (c *client) AuthSteam(ctx context.Context, uid string, values url.Values, opts *twitchhttp.ReqOpts) (string, error) {
	path := fmt.Sprintf("/%s/%s/platforms/steam/auth?%s", ver, uid, values.Encode())
	res, err := c.do(ctx, "GET", path, "authSteam", 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
}

// CallbackSteam creates a new Steam connection given a user ID, a Steam
// OAuth token, and a Steam OAuth verifier. Requires an authorization token.
func (c *client) CallbackSteam(ctx context.Context, uid string, values url.Values, opts *twitchhttp.ReqOpts) error {
	path := fmt.Sprintf("/%s/%s/platforms/steam/callback?%s", ver, uid, values.Encode())
	res, err := c.do(ctx, "GET", path, "callbackSteamUser", opts)
	if err != nil {
		return err
	}
	defer res.Body.Close()

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

	return nil
}

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

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

}

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

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

	return nil
}
