package beisen

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"

	"github.com/pingcap-inc/it-automation/internal/pkg/redis"
)

const (
	TokenUrl  = "https://openapi.italent.cn/token"
	UsersInfo = "https://openapi.italent.cn/TenantBaseExternal/api/v5/Employee/GetBasicInfoByIds"
	Prefix    = "beisen"
	Token     = "token"
)

type Beisen interface {
	GetToken() string
	GetUsersInfo(ids []int) *BsUsersInfoRes
}

var _ Beisen = (*beisenService)(nil)

type beisenService struct {
}

func NewBeisenService() Beisen {
	return &beisenService{}
}

func (bs *beisenService) GetToken() string {
	method := "POST"
	restore := &redis.Redis{}
	key, err := restore.GetRedis(Prefix).GetKey(Token)
	if err != nil {
		if err.Error() != "key not found" {
			log.Errorf("Error when get tokenInR from redis: %v", err)

			return ""
		}
	}
	if key != "" {
		return key
	}

	marshal, err := json.Marshal(BsTokenBody{
		GrantType: viper.Get("beisen.grant_type").(string),
		AppKey:    viper.Get("beisen.key").(string),
		AppSecret: viper.Get("beisen.secret").(string),
	})
	if err != nil {
		log.Errorf("Error when marshal json: %v", err)

		return ""
	}

	client := &http.Client{}
	req, err := http.NewRequest(method, TokenUrl, bytes.NewReader(marshal))

	if err != nil {
		log.Errorf("Error when create request: %v", err)

		return ""
	}
	req.Header.Add("Content-Type", "application/json")

	res, err := client.Do(req)
	if err != nil {
		log.Errorf("Error when send request: %v", err)

		return ""
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Errorf("Error when read response body: %v", err)

		return ""
	}
	result := &BsTokenRes{}
	err = json.Unmarshal(body, result)
	if err != nil {
		log.Errorf("Error when unmarshal json: %v", err)

		return ""
	}
	err = restore.GetRedis(Prefix).SetKey(Token, result.AccessToken, time.Hour)
	if err != nil {
		log.Errorf("Error when save token into redis: %v", err)
	}

	return result.AccessToken
}

func (bs *beisenService) GetUsersInfo(ids []int) *BsUsersInfoRes {
	method := "POST"

	marshal, err := json.Marshal(BsUsersInfoBody{
		OIds:            ids,
		IsWithDeleted:   false,
		Columns:         []string{"Name", "Email"},
		EnableTranslate: false,
	})
	if err != nil {
		log.Errorf("Error when marshal json: %v", err)

		return nil
	}

	client := &http.Client{}
	req, err := http.NewRequest(method, UsersInfo, bytes.NewReader(marshal))

	if err != nil {
		log.Errorf("Error when create request: %v", err)

		return nil
	}
	token := bs.GetToken()
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))

	res, err := client.Do(req)
	if err != nil {
		log.Errorf("Error when send request: %v", err)

		return nil
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Errorf("Error when read response body: %v", err)

		return nil
	}
	result := &BsUsersInfoRes{}
	err = json.Unmarshal(body, result)
	if err != nil {
		log.Errorf("Error when unmarshal json: %v", err)

		return nil
	}

	return result
}
