package superset

import (
	"encoding/json"
	"io/ioutil"
	"net/http"

	"github.com/fiskerinc/cloud-services/pkg/httpclient"
	"github.com/fiskerinc/cloud-services/pkg/redis"
	"github.com/pkg/errors"
)

var loginFunc = login

type supersetRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
	Provider string `json:"provider"`
	Refresh  bool   `json:"refresh"`
}

type supersetResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
}

func GetAccessToken(r redis.Client) (string, error) {
	token, err := getCachedAccToken(r)
	if err != nil && !errors.Is(err, errTokenNotFound) {
		return "", err
	}
	if err == nil {
		return token, nil
	}

	token, err = login(r)
	if err != nil {
		return "", err
	}

	return token, nil
}

func login(r redis.Client) (string, error) {
	headers := http.Header{}
	headers.Add("Content-Type", "application/json")
	resp, err := httpclient.Post(
		host+"/security/login",
		supersetRequest{
			Username: accUserName,
			Password: password,
			Provider: "db",
			Refresh:  true,
		},
		headers,
	)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return "", errors.Errorf("superset login answered with status: %s", resp.Status)
	}

	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", errors.WithStack(err)
	}

	sresp := supersetResponse{}
	err = json.Unmarshal(b, &sresp)
	if err != nil {
		return "", errors.WithStack(err)
	}

	err = r.Set(redis.SupersetAccTokenKey, sresp.AccessToken)
	if err != nil {
		return "", err
	}

	return sresp.AccessToken, nil
}

// SetLoginFunc must be useful for testing.
func SetLoginFunc(login func(r redis.Client) (string, error)) {
	loginFunc = login
}
