package api

import (
	"box-cost/log"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"net/http"
	"runtime"
	"strconv"
	"strings"

	jwt "github.com/appleboy/gin-jwt/v2"
	"github.com/gin-gonic/gin"
)

// Handler 包装http处理函数
type Handler func(c *gin.Context, apictx *ApiSession) (interface{}, error)

// JWTHander JWT授权的http处理函数
type JWTHander func(c *gin.Context, apictx *ApiSession) (interface{}, error)

// ResultWrapper 统一返回结果处理
func ResultWrapper(handle Handler, svc *Service) gin.HandlerFunc {

	return func(c *gin.Context) {

		defer func() {
			if r := recover(); r != nil {

				fmt.Println("recover success.")
				fmt.Println(r)

				buf := make([]byte, 1<<16)
				runtime.Stack(buf, true)
				fmt.Println("buf", string(buf))

				c.JSON(http.StatusOK, NewFailResultWithData("系统异常", r))
			}
		}()

		data, err := handle(c, &ApiSession{Svc: svc, User: nil})
		if err != nil {
			httpErr, ok := err.(HTTPError)
			if ok {
				c.JSON(http.StatusOK, NewFailResultWithCode(httpErr.Error(), httpErr.Code))
				return
			}
			c.JSON(http.StatusOK, NewFailResult(err.Error()))
			return
		}

		if data != nil {
			c.JSON(http.StatusOK, NewOkResult(data))
		}
	}
}

// ResultJWTWrapper JWT授权处理handler
func ResultJWTWrapper(handle JWTHander, svc *Service) gin.HandlerFunc {

	return func(c *gin.Context) {

		defer func() {
			if r := recover(); r != nil {
				fmt.Println("recover success.")
				fmt.Println(r)

				buf := make([]byte, 1<<16)
				runtime.Stack(buf, true)
				fmt.Println("buf", string(buf))

				c.JSON(http.StatusOK, NewFailResultWithData("系统异常", r))
			}
		}()

		claims := jwt.ExtractClaims(c)

		var usr *JWTUser

		if claims["id"] != nil {
			id := claims["id"].(string)
			name := claims["phone"].(string)
			role := claims["role"].(string)
			parent := claims["parent"].(string)
			state := int32(claims["state"].(float64))

			usr = &JWTUser{ID: id, Phone: name, Parent: parent, Role: role, State: state}
		}
		var apis = &ApiSession{
			Svc:  svc,
			User: usr,
		}
		data, err := handle(c, apis)

		if err != nil {
			fmt.Println(err)
			httpErr, ok := err.(HTTPError)
			if ok {
				c.JSON(http.StatusOK, NewFailResultWithCode(httpErr.Error(), httpErr.Code))
				return
			}

			c.JSON(http.StatusOK, NewFailResult(err.Error()))
			return
		}
		if data != nil {
			c.JSON(http.StatusOK, NewOkResult(data))
		}
	}
}

// ResultJWTTestWrapper test 默认一个测试用户 JWT授权处理handler
func ResultJWTTestWrapper(handle JWTHander, svc *Service) gin.HandlerFunc {

	return func(c *gin.Context) {

		defer func() {
			if r := recover(); r != nil {

				fmt.Println("recover success.")
				fmt.Println(r)

				buf := make([]byte, 1<<16)
				runtime.Stack(buf, true)
				fmt.Println("buf", string(buf))

				c.JSON(http.StatusOK, NewFailResultWithData("error", r))
			}
		}()

		var usr *JWTUser = &JWTUser{ID: svc.DebugUserId, Phone: svc.DebugUserPhone, Parent: svc.DebugUserId, Role: svc.DebugUserRole}

		data, err := handle(c, &ApiSession{Svc: svc, User: usr})

		if err != nil {
			fmt.Println(err)
			httpErr, ok := err.(HTTPError)
			if ok {
				c.JSON(http.StatusOK, NewFailResultWithCode(httpErr.Error(), httpErr.Code))
				return
			}

			c.JSON(http.StatusOK, NewFailResult(err.Error()))
			return
		}
		c.JSON(http.StatusOK, NewOkResult(data))
	}
}

// ResultSuc 成功
func ResultSuc(c *gin.Context, data interface{}) {
	c.JSON(http.StatusOK, NewOkResult(data))
}

// ResultFail 失败
func ResultFail(c *gin.Context, msg string) {
	c.JSON(http.StatusOK, NewFailResult(msg))
}

// ResultFail401 失败2
func ResultFail401(c *gin.Context, msg string, data interface{}) {
	c.JSON(http.StatusOK, &HTTPResult{ErrorNo: 401, Result: data, ErrorDesc: msg})
}

// UtilMd5 结算md5的值
func UtilMd5(s string) string {
	data := []byte(s)
	has := md5.Sum(data)
	return fmt.Sprintf("%x", has)
}

// UtilQueryPageSize 分页数据
func UtilQueryPageSize(c *gin.Context) (page int64, size int64, query map[string]interface{}) {
	p := c.Query("page")
	s := c.Query("size")
	q := c.Query("query")

	var _page = 1

	if len(p) > 0 {
		_page, _ = strconv.Atoi(p)
	}
	page = int64(_page)

	var _size = 10
	if len(s) > 0 {
		_size, _ = strconv.Atoi(s)
	}
	size = int64(_size)

	if len(q) > 0 {
		json.Unmarshal([]byte(q), &query)
	} else {
		query = map[string]interface{}{}
	}
	return
}

func UtilQueryPageSize2(c *gin.Context) (page int64, size int64, query map[string]interface{}, fields []string) {
	p := c.Query("page")
	s := c.Query("size")
	q := c.Query("query")
	f := c.Query("fields")

	var _page = 1

	if len(p) > 0 {
		_page, _ = strconv.Atoi(p)
	}
	page = int64(_page)

	var _size = 10
	if len(s) > 0 {
		_size, _ = strconv.Atoi(s)
	}
	size = int64(_size)

	if len(q) > 0 {
		json.Unmarshal([]byte(q), &query)
	} else {
		query = map[string]interface{}{}
	}
	if len(f) > 0 {
		fields = strings.Split(f, ",")
	} else {
		fields = []string{}
	}
	return
}

// HTTPResult 客户端统一返回结构体
type HTTPResult struct {
	ErrorNo   int32       `json:"errorNo"`
	Result    interface{} `json:"result"`
	ErrorDesc string      `json:"errorDesc"`
}

func (err HTTPResult) Error() string {
	return err.ErrorDesc
}

// HTTPError 统一错误处理
type HTTPError struct {
	Code    int32  `json:"code"`
	Message string `json:"message"`
}

func (err HTTPError) Error() string {
	return err.Message
}

// NewOkResult 创建正确结果
func NewOkResult(obj interface{}) *HTTPResult {
	return &HTTPResult{ErrorNo: 200, Result: obj}
}

// NewFailResult 创建错误结构
func NewFailResult(desc string) *HTTPResult {
	return &HTTPResult{ErrorNo: 500, Result: nil, ErrorDesc: desc}
}

// NewFailResultWithData 创建错误返回结果
func NewFailResultWithData(desc string, data interface{}) *HTTPResult {
	return &HTTPResult{ErrorNo: 500, Result: data, ErrorDesc: desc}
}

// NewFailResultWithCode 创建错误结构
func NewFailResultWithCode(desc string, code int32) *HTTPResult {
	return &HTTPResult{ErrorNo: code, Result: nil, ErrorDesc: desc}
}

// NewError NewError
func NewError(desc string) HTTPError {
	return HTTPError{Code: 500, Message: desc}
}

func NewLogError(desc string) HTTPError {
	pc, file, line, _ := runtime.Caller(1)
	log.Errorf("%s:%d=>%s %v", file, line, runtime.FuncForPC(pc).Name(), desc)

	return HTTPError{Code: 500, Message: desc}
}

func NewLogWithError(err error) HTTPError {
	pc, file, line, _ := runtime.Caller(1)
	log.Errorf("%s:%d=>%s %s", file, line, runtime.FuncForPC(pc).Name(), err.Error())

	return HTTPError{Code: 500, Message: err.Error()}
}

// NewErrorWithCode NewErrorWithCode
func NewErrorWithCode(desc string, code int32) HTTPError {
	return HTTPError{Code: code, Message: desc}
}

// JWTUser jwt登录用户
type JWTUser struct {
	ID     string `json:"id"`
	Parent string `json:"parent"`
	Phone  string `json:"phone"`
	Role   string `json:"role"`
	Perms  string `json:"perms"`
	State  int32  `json:"state"`
}

func UtilQueryMap(c *gin.Context) map[string]interface{} {
	query := map[string]interface{}{}
	q := c.Query("query")
	if len(q) > 0 {
		json.Unmarshal([]byte(q), &query)
	}
	return query
}

func BoolValue(value bool) *bool {
	return &value
}
func Int32Value(value int32) *int32 {
	return &value
}
func Float32Value(value float32) *float32 {
	return &value
}
func Float64Value(value float64) *float64 {
	return &value
}