package github

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/vx3r/wg-gen-web/model"
	"golang.org/x/oauth2"
	oauth2Github "golang.org/x/oauth2/github"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

// Github in order to implement interface, struct is required
type Github struct{}

var (
	oauth2Config *oauth2.Config
)

// Setup validate provider
func (o *Github) Setup() error {
	oauth2Config = &oauth2.Config{
		ClientID:     os.Getenv("OAUTH2_CLIENT_ID"),
		ClientSecret: os.Getenv("OAUTH2_CLIENT_SECRET"),
		RedirectURL:  os.Getenv("OAUTH2_REDIRECT_URL"),
		Scopes:       []string{"user"},
		Endpoint:     oauth2Github.Endpoint,
	}

	return nil
}

// CodeUrl get url to redirect client for auth
func (o *Github) CodeUrl(state string) string {
	return oauth2Config.AuthCodeURL(state)
}

// Exchange exchange code for Oauth2 token
func (o *Github) Exchange(code string) (*oauth2.Token, error) {
	oauth2Token, err := oauth2Config.Exchange(context.TODO(), code)
	if err != nil {
		return nil, err
	}

	return oauth2Token, nil
}

// UserInfo get token user
func (o *Github) UserInfo(oauth2Token *oauth2.Token) (*model.User, error) {
	// https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/

	// we have the token, lets get user information
	req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", fmt.Sprintf("token %s", oauth2Token.AccessToken))
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("http status %s expect 200 OK", resp.Status)
	}

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var data map[string]interface{}
	err = json.Unmarshal(bodyBytes, &data)
	if err != nil {
		return nil, err
	}

	// get some infos about user
	user := &model.User{}

	if val, ok := data["name"]; ok && val != nil {
		user.Name = val.(string)
	}
	if val, ok := data["email"]; ok && val != nil {
		user.Email = val.(string)
	}
	if val, ok := data["html_url"]; ok && val != nil {
		user.Profile = val.(string)
	}

	// openid specific
	user.Sub = "github is not an openid provider"
	user.Issuer = "https://github.com"
	user.IssuedAt = time.Now().UTC()

	return user, nil
}