// Package oauth ...
//
// Description : oauth ...
//
// Author : go_developer@163.com<张德满>
//
// Date : 2022/01/17 12:18 AM
package oauth

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"

	"github.com/pkg/errors"

	"github.com/ddliu/go-httpclient"
)

// NewOAuth 获取OAuth实例
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2022/1/17 12:19 AM
func NewOAuth(cfg Config) *OAuth {
	return &OAuth{
		cfg: cfg,
	}
}

// OAuth 管理
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2022/1/17 12:19 AM
type OAuth struct {
	cfg Config
}

// GetAuthorizationPageURL 获取授权页面的URL
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2022/1/17 12:33 AM
func (o *OAuth) GetAuthorizationPageURL(scope string, responseType string) string {
	return fmt.Sprintf(
		"%s%s?client_id=%s&redirect_uri=%s&scope=%s&response_type=%s",
		o.cfg.Domain,
		o.cfg.AuthorizationPageURI,
		o.cfg.ClientID,
		url.QueryEscape(o.cfg.CallbackURL),
		scope,
		responseType,
	)
}

// ApplyAccessTokenByCode 通过code申请授权token
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2022/1/17 12:35 AM
func (o *OAuth) ApplyAccessTokenByCode(code string, receiver interface{}) error {
	// OAuth 授权回调
	parameter := map[string]string{
		"code":          code,
		"client_id":     o.cfg.ClientID,
		"client_secret": o.cfg.ClientSecret,
		"grant_type":    "authorization_code",
	}
	client := httpclient.NewHttpClient()
	client.WithHeader("Accept", "application/json")
	resp, err := client.Post(o.cfg.Domain+o.cfg.GetAccessTokenURI+"?grant_type=authorization_code", parameter)
	if nil != err {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("【%v】%v", resp.StatusCode, resp.Status)
	}
	body, err := io.ReadAll(resp.Body)
	if nil != err {
		return errors.New("读取响应体失败: " + err.Error())
	}
	decoder := json.NewDecoder(bytes.NewReader(body))
	decoder.UseNumber()
	return decoder.Decode(receiver)
}

// ValidateAccessToken 验证授权token
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2022/1/17 12:43 AM
func (o *OAuth) ValidateAccessToken(token string, receiver interface{}) error {
	if nil != o.cfg.FormatAccessTokenFunc {
		token = o.cfg.FormatAccessTokenFunc(token)
	}
	parameter := make(map[string]string)
	client := httpclient.NewHttpClient()
	client.WithHeader("Accept", "application/json")
	if o.cfg.UseAuthorization {
		client.WithHeader("Authorization", "token "+token)
	} else {
		parameter[o.cfg.AccessTokenKey] = token
	}
	resp, err := client.Get("https://git.zhangdeman.cn/api/v1/user?grant_type=authorization_code", parameter)
	if nil != err {
		return err
	}
	body, err := io.ReadAll(resp.Body)
	if nil != err {
		return errors.New("读取响应体失败 : " + err.Error())
	}
	decoder := json.NewDecoder(bytes.NewReader(body))
	decoder.UseNumber()
	return decoder.Decode(receiver)
}

// GetUserDetailByToken 根据 token 获取用户详情
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2022/1/17 12:55 AM
func (o *OAuth) GetUserDetailByToken(token string, receiver interface{}) error {
	return o.ValidateAccessToken(token, receiver)
}