package ups_sdk

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-resty/resty/v2"
	"net/http"
	"net/url"
	"path"
	"strconv"
)

const (
	registerUserUrl       = "/ups/api/v1/user/register"
	deleteUserUrl         = "/ups/api/v1/user/delete"
	identifyUrl           = "/ups/api/v1/user/identify"
	updateUserUserNameUrl = "/ups/api/v1/user/userName/update"
	updateUserPasswordUrl = "/ups/api/v1/user/password/update"
	mergeUserUrl          = "/ups/api/v1/user/merge"
	getUsersUrl           = "/ups/api/v1/user/query"
	getMessagesUrl        = "/ups/api/v1/message/query"
)

type API struct {
	baseUrl    string
	httpClient *resty.Client
}

// NewAPI 创建API
func NewAPI(baseUrl string) (*API, error) {
	_, err := url.ParseRequestURI(baseUrl)
	if err != nil {
		return nil, err
	}

	return &API{
		baseUrl:    baseUrl,
		httpClient: resty.New().SetTimeout(HttpClientTimeout),
	}, nil
}

type SaveUserTransactionFunc func() error
type SaveUserRollbackFunc func() error
type SaveUserCommitFunc func() error

type RegisterUserFlowParams struct {
	UserName                string
	Password                string
	SaveUserTransactionFunc SaveUserTransactionFunc
	SaveUserRollbackFunc    SaveUserRollbackFunc
	SaveUserCommitFunc      SaveUserCommitFunc
}

func (params *RegisterUserFlowParams) Check() error {
	if IsStringEmpty(params.UserName) {
		return errors.New("没有传递用户名")
	}

	if IsStringEmpty(params.Password) {
		return errors.New("没有传递密码")
	}

	if params.SaveUserTransactionFunc == nil {
		return errors.New("没有传递保存用户名事务函数")
	}

	if params.SaveUserRollbackFunc == nil {
		return errors.New("没有传递保存用户名事务回滚函数")
	}

	if params.SaveUserCommitFunc == nil {
		return errors.New("没有传递保存用户名事务回滚函数")
	}

	return nil
}

// RegisterUserFlow 注册用户流程
func (api *API) RegisterUserFlow(params *RegisterUserFlowParams) error {

	return nil
}

// RegisterUser 注册用户
func (api *API) RegisterUser(userName string, password string) error {
	if IsStringEmpty(userName) {
		return errors.New("没有传递用户名")
	}

	if IsStringEmpty(password) {
		return errors.New("没有传递密码")
	}

	return api.registerUser(userName, password)
}

// DeleteUser 删除用户
func (api *API) DeleteUser(userName string) error {
	if IsStringEmpty(userName) {
		return errors.New("没有传递用户名")
	}

	return api.deleteUser(userName)
}

// Identify 认证用户
func (api *API) Identify(userName string, password string) error {
	if IsStringEmpty(userName) {
		return errors.New("没有传递用户名")
	}

	if IsStringEmpty(password) {
		return errors.New("没有传递密码")
	}

	return api.identify(userName, password)
}

// UpdateUserUserName 修改用户用户名
func (api *API) UpdateUserUserName(oldUserName string, newUserName string) error {
	if IsStringEmpty(oldUserName) {
		return errors.New("没有传递旧用户名")
	}

	if IsStringEmpty(newUserName) {
		return errors.New("没有传递新用户名")
	}

	return api.updateUserUserName(oldUserName, newUserName)
}

// UpdateUserPassword 修改用户密码
func (api *API) UpdateUserPassword(userName string, newPassword string) error {
	if IsStringEmpty(userName) {
		return errors.New("没有传递用户名")
	}

	if IsStringEmpty(newPassword) {
		return errors.New("没有传递新密码")
	}

	return api.updateUserPassword(userName, newPassword)
}

// MergeUser 合并用户,实际作用校验from和to用户存在性,保留to用户,删除from用户
func (api *API) MergeUser(fromUserName string, toUserName string) error {
	if IsStringEmpty(fromUserName) {
		return errors.New("没有传递被合并的用户名")
	}

	if IsStringEmpty(toUserName) {
		return errors.New("没有传递合并到的用户名")
	}

	return api.mergeUser(fromUserName, toUserName)
}

// GetUsers 查询用户
func (api *API) GetUsers(userName string, pageNo int, pageSize int) (*QueryUserResult, error) {
	return api.getUsers(userName, pageNo, pageSize)
}

// GetMessages 查询消息
func (api *API) GetMessages(topic string, startSendTime string, endSendTime string, pageNo int, pageSize int) (*QueryMessageResult, error) {
	return api.getMessages(topic, startSendTime, endSendTime, pageNo, pageSize)
}

func (api *API) registerUser(userName string, password string) error {
	requestUrl := path.Join(api.baseUrl, registerUserUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetBody(&RegisterUserRequest{
			UserName: userName,
			Password: password,
		}).
		Post(requestUrl)
	if err != nil {
		return err
	}

	if resp.IsError() {
		return fmt.Errorf("请求失败: URL %s, Method %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodPost, resp.StatusCode(), resp.Status())
	}

	response := new(RegisterUserResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return err
	}

	if !response.Success {
		return fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodPost, response.Msg)
	}

	return nil
}

func (api *API) deleteUser(userName string) error {
	requestUrl := path.Join(api.baseUrl, deleteUserUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetQueryParam("userName", userName).
		Delete(requestUrl)
	if err != nil {
		return err
	}

	if resp.IsError() {
		return fmt.Errorf("请求失败: URL %s, Method: %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodDelete, resp.StatusCode(), resp.Status())
	}

	response := new(DeleteUserResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return err
	}

	if !response.Success {
		return fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodDelete, response.Msg)
	}

	return nil
}

func (api *API) identify(userName string, password string) error {
	requestUrl := path.Join(api.baseUrl, identifyUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetBody(&IdentifyRequest{
			UserName: userName,
			Password: password,
		}).
		Post(requestUrl)
	if err != nil {
		return err
	}

	if resp.IsError() {
		return fmt.Errorf("请求失败: URL %s, Method %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodPost, resp.StatusCode(), resp.Status())
	}

	response := new(IdentifyResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return err
	}

	if !response.Success {
		return fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodPost, response.Msg)
	}

	return nil
}

func (api *API) updateUserUserName(oldUserName string, newUserName string) error {
	requestUrl := path.Join(api.baseUrl, updateUserUserNameUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetBody(&UpdateUserUserNameRequest{
			OldUserName: oldUserName,
			NewUserName: newUserName,
		}).
		Put(requestUrl)
	if err != nil {
		return err
	}

	if resp.IsError() {
		return fmt.Errorf("请求失败: URL %s, Method %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodPut, resp.StatusCode(), resp.Status())
	}

	response := new(UpdateUserUserNameResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return err
	}

	if !response.Success {
		return fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodPut, response.Msg)
	}

	return nil
}

func (api *API) updateUserPassword(userName string, newPassword string) error {
	requestUrl := path.Join(api.baseUrl, updateUserPasswordUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetBody(&UpdateUserPasswordRequest{
			UserName:    userName,
			NewPassword: newPassword,
		}).
		Put(requestUrl)
	if err != nil {
		return err
	}

	if resp.IsError() {
		return fmt.Errorf("请求失败: URL %s, Method %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodPut, resp.StatusCode(), resp.Status())
	}

	response := new(UpdateUserPasswordResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return err
	}

	if !response.Success {
		return fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodPut, response.Msg)
	}

	return nil
}

func (api *API) mergeUser(fromUserName string, toUserName string) error {
	requestUrl := path.Join(api.baseUrl, mergeUserUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetBody(&MergeUserRequest{
			FromUserName: fromUserName,
			ToUserName:   toUserName,
		}).
		Post(requestUrl)
	if err != nil {
		return err
	}

	if resp.IsError() {
		return fmt.Errorf("请求失败: URL %s, Method %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodPost, resp.StatusCode(), resp.Status())
	}

	response := new(MergeUserResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return err
	}

	if !response.Success {
		return fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodPost, response.Msg)
	}

	return nil
}

func (api *API) getUsers(userName string, pageNo int, pageSize int) (*QueryUserResult, error) {
	requestUrl := path.Join(api.baseUrl, getUsersUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetQueryParam("userName", userName).
		SetQueryParam("pageNo", strconv.Itoa(pageNo)).
		SetQueryParam("pageSize", strconv.Itoa(pageSize)).
		Get(requestUrl)
	if err != nil {
		return nil, err
	}

	if resp.IsError() {
		return nil, fmt.Errorf("请求失败: URL %s, Method %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodGet, resp.StatusCode(), resp.Status())
	}

	response := new(GetUsersResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return nil, err
	}

	if !response.Success {
		return nil, fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodGet, response.Msg)
	}

	return &response.QueryUserResult, nil
}

func (api *API) getMessages(topic string, startSendTime string, endSendTime string, pageNo int, pageSize int) (*QueryMessageResult, error) {
	requestUrl := path.Join(api.baseUrl, getMessagesUrl)

	resp, err := api.httpClient.R().
		SetHeader("Content-Type", "application/json").
		SetQueryParam("topic", topic).
		SetQueryParam("startSendTime", startSendTime).
		SetQueryParam("endSendTime", endSendTime).
		SetQueryParam("pageNo", strconv.Itoa(pageNo)).
		SetQueryParam("pageSize", strconv.Itoa(pageSize)).
		Get(requestUrl)
	if err != nil {
		return nil, err
	}

	if resp.IsError() {
		return nil, fmt.Errorf("请求失败: URL %s, Method %s, Status Code %d, Status %s\n",
			requestUrl, http.MethodGet, resp.StatusCode(), resp.Status())
	}

	response := new(GetMessagesResponse)
	err = json.Unmarshal(resp.Body(), response)
	if err != nil {
		return nil, err
	}

	if !response.Success {
		return nil, fmt.Errorf("请求失败: URL %s, Method: %s, Error %s\n",
			requestUrl, http.MethodGet, response.Msg)
	}

	return &response.QueryMessageResult, nil
}