package kong

import (
	"ai_developer_admin/models"
	"bytes"
	"encoding/json"
	"errors"
	"github.com/beego/beego/v2/core/logs"
	beego "github.com/beego/beego/v2/server/web"
	"io"
	"net/http"
)

func kongApi(path string, method string, payload io.Reader, headers map[string]string) ([]byte, error) {
	client := &http.Client{}

	base_url, _ := beego.AppConfig.String("kongadminurl")

	url := base_url + "/" + path

	reqest, err := http.NewRequest(method, url, payload)
	for key, value := range headers {
		reqest.Header.Add(key, value)
	}
	//reqest.Header.Add("Content-Type", "application/json")
	resp, err := client.Do(reqest)
	if err != nil {
		return nil, err
	}
	//fmt.Printf("resp status code: %s\n", resp.Body)
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

func CreateUser(user *models.User) (*models.CreateUserResponse, error) {
	createUser := models.CreateUserRequest{
		Username: user.Username,
		CustomId: user.CustomId,
	}
	payload := new(bytes.Buffer)
	json.NewEncoder(payload).Encode(createUser)
	var err error
	var data []byte
	headers := map[string]string{
		"Content-Type": "application/json",
	}
	data, err = kongApi("consumers", "POST", payload, headers)
	if err != nil {
		return nil, err
	}
	logs.Debug("kong CreateUser", string(data))
	var response models.CreateUserResponse
	if err = json.Unmarshal(data, &response); err != nil {
		return nil, err
	}
	return &response, err
}

func CreateApiKey(user *models.User) (*models.CreateApiKeyResponse, error) {
	var err error
	var data []byte
	path := "consumers/" + user.Username + "/key-auth"
	data, err = kongApi(path, "POST", nil, nil)
	if err != nil {
		return nil, err
	}
	logs.Debug("kong CreateApiKey", string(data))
	var response models.CreateApiKeyResponse
	if err = json.Unmarshal(data, &response); err != nil {
		return nil, err
	}
	return &response, err
}

func DelateApiKey(username string, id string) error {
	var err error
	var data []byte
	path := "consumers/" + username + "/key-auth" + "/" + id
	headers := map[string]string{
		"Content-Type": "application/json",
	}
	data, err = kongApi(path, "DELETE", nil, headers)
	if err != nil {
		return err
	}
	logs.Debug("kong DelateApiKey", string(data))
	return nil
}

func ListApikeys(username string) ([]models.CreateApiKeyResponse, error) {
	var err error
	var data []byte
	path := "consumers/" + username + "/key-auth"
	data, err = kongApi(path, "GET", nil, nil)
	if err != nil {
		return nil, err
	}
	logs.Debug("kong ListApikeys", string(data))
	var response models.APIKeys
	if err = json.Unmarshal(data, &response); err != nil {
		return nil, err
	}
	return response.Data, err
}

func CreateJwt(user *models.User) (*models.JWTResponse, []byte, error) {
	var err error
	var data []byte
	path := "consumers/" + user.Username + "/jwt"
	headers := map[string]string{}
	data, err = kongApi(path, "POST", nil, headers)
	if err != nil {
		return nil, nil, err
	}
	logs.Debug("kong CreateJwt", string(data))
	var response models.JWTResponse
	if err = json.Unmarshal(data, &response); err != nil {
		return nil, nil, err
	}
	return &response, data, err
}

func DelateJWT(username string, id string) error {
	var err error
	var data []byte
	path := "consumers/" + username + "/jwt" + "/" + id
	data, err = kongApi(path, "DELETE", nil, nil)
	if err != nil {
		return err
	}
	logs.Debug("kong DelateApiKey", string(data))
	return nil
}

func ListJWT(username string) ([]models.JWTResponse, error) {
	var err error
	var data []byte
	path := "consumers/" + username + "/jwt"
	data, err = kongApi(path, "GET", nil, nil)
	if err != nil {
		return nil, err
	}
	logs.Debug("kong ListJWT", string(data))
	var response models.JWTS
	if err = json.Unmarshal(data, &response); err != nil {
		return nil, err
	}
	return response.Data, err
}

func SetRateLimit(user *models.User, level *models.UserLevel, pluginId string) (*models.Plugin, error) {
	var err error
	var data []byte
	path := "consumers/" + user.Username + "/plugins" + "/" + pluginId
	headers := map[string]string{
		"Content-Type": "application/json",
	}
	method := "POST"
	if pluginId != "" {
		method = "PATCH"
	}
	configData := struct {
		Second int   `json:"second,omitempty"`
		Minute int   `json:"minute,omitempty"`
		Hour   int   `json:"hour,omitempty"`
		Day    int   `json:"day,omitempty"`
		Month  int   `json:"month,omitempty"`
		Year   int64 `json:"year,omitempty"`
	}{}

	if level.RateLimitSecond > 0 {
		configData.Second = level.RateLimitSecond
	}
	if level.RateLimitMinute > 0 {
		configData.Minute = level.RateLimitMinute
	}
	if level.RateLimitHour > 0 {
		configData.Hour = level.RateLimitHour
	}
	if level.RateLimitDay > 0 {
		configData.Day = level.RateLimitDay
	}
	if level.RateLimitMonth > 0 {
		configData.Month = level.RateLimitMonth
	}
	if level.RateLimitYear > 0 {
		configData.Year = level.RateLimitYear
	}
	jsonData := struct {
		Name   string      `json:"name"`
		Config interface{} `json:"config"`
	}{
		Name:   "rate-limiting",
		Config: configData,
	}

	payload := new(bytes.Buffer)
	json.NewEncoder(payload).Encode(jsonData)
	logs.Debug("SetRateLimit = ", payload.String())
	data, err = kongApi(path, method, payload, headers)
	if err != nil {
		logs.Debug("kong SetRateLimit", err.Error())
		return nil, err
	}
	logs.Debug("kong SetRateLimit", string(data))
	var response models.Plugin
	if err = json.Unmarshal(data, &response); err != nil {
		return nil, err
	}
	if response.Code != 0 {
		return nil, errors.New(response.Message)
	}
	return &response, nil
}

func ListPlugins(user *models.User) ([]models.Plugin, error) {
	var err error
	var data []byte
	path := "consumers/" + user.Username + "/plugins"
	headers := map[string]string{
		"Content-Type": "application/json",
	}
	var response models.Plugins
	data, err = kongApi(path, "GET", nil, headers)
	if err != nil {
		logs.Debug("kong SetRateLimit", err.Error())
		return response.Data, err
	}
	logs.Debug("kong CreateJwt", string(data))

	if err = json.Unmarshal(data, &response); err != nil {
		return response.Data, err
	}
	return response.Data, nil
}
