package handle

import (
	"context"
	"encoding/json"
	er "errors"
	"fmt"
	"git.echol.cn/loser/logger/log"
	"github.com/go-oauth2/oauth2/v4"
	"github.com/go-oauth2/oauth2/v4/errors"
	"miniapp/client"
	"miniapp/model/app"
	"miniapp/model/cache"
	"miniapp/model/common/constant"
	"miniapp/service"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// UserAuthorizationHandler 获取用户Id
func UserAuthorizationHandler(w http.ResponseWriter, r *http.Request) (userId string, err error) {
	loginType := constant.LoginType(r.FormValue("type"))           // 登录类型
	userIdentity := constant.UserIdentity(r.FormValue("identity")) // 身份类型
	account := r.FormValue("username")                             // 用户传入账号(或者授权Code)
	nikeName := r.FormValue("nickName")                            // 昵称
	avatarUrl := r.FormValue("avatarUrl")                          // 头像

	log.Debugf("预处理用户登录请求，身份类型: %v => 登录类型: %s => 账号: %v", userIdentity, loginType, account)

	var roleCode []string
	// 处理用户Id
	switch userIdentity {
	case constant.UserIdentityAdmin:
		// 管理员
	case constant.UserIdentityUser:
		// 普通用户
		userId, err = getUser(account, loginType, nikeName, avatarUrl)
	default:
		err = er.New("未知的用户身份类型")
	}

	if err != nil {
		return
	}

	// 组装缓存用户信息
	m := cache.UserInfo{
		RoleCodes: strings.Join(roleCode, ","),
		UserId:    userId,
		UserType:  userIdentity.String(),
	}
	userInfo, err := m.String()
	if err != nil {
		err = errors.New("登录失败，请联系管理员")
		return
	}
	if err = client.Redis.Set(context.Background(), fmt.Sprintf("%s%v", constant.OAuth2UserCacheKey, userId), userInfo, time.Hour*24*7).Err(); err != nil {
		log.Errorf("缓存用户信息失败，用户ID：%v，错误信息：%s", userId, err.Error())
		err = errors.New("登录失败，请联系管理员")
		return
	}

	return
}

// LoginWithPassword 账号密码登录模式
func LoginWithPassword(ctx context.Context, clientId, userId, password string) (userID string, err error) {
	log.Debugf("[%v]处理登录请求，用户Id：%s --> %s", clientId, userId, password)

	userID = userId
	return
}

// CheckClient 检查是否允许该客户端通过该授权模式请求令牌
func CheckClient(clientID string, grant oauth2.GrantType) (allowed bool, err error) {
	// 解出租户Id和传入的客户端Id
	c := app.OAuth2Client{ClientId: clientID}

	// 查询客户端配置信息
	if err = service.ServiceGroupApp.AppServiceGroup.Oauth2ClientService.FindOne(&c); err != nil {
		log.Errorf("客户端信息查询失败: %v", err.Error())
		err = errors.New("客户端信息查询失败: " + err.Error())
		allowed = false
		return
	}
	// 判断是否包含授权范围
	allowed = strings.Contains(c.Grant, string(grant))
	if !allowed {
		err = errors.New("不受允许的grant_type")
	}
	return
}

// ExtensionFields 自定义响应Token的扩展字段
func ExtensionFields(ti oauth2.TokenInfo) (fieldsValue map[string]any) {
	fieldsValue = map[string]any{}
	fieldsValue["license"] = "Made By Lee"

	// 取出用户信息
	var userInfo app.User
	tid, _ := strconv.Atoi(ti.GetUserID())
	userInfo.ID = uint(tid)
	//if err := repository.User().GetUser(&userInfo); err != nil {
	//	return
	//}
	service.ServiceGroupApp.AppServiceGroup.UserService.GetUser(&userInfo)
	fieldsValue["newUser"] = time.Now().Sub(userInfo.CreatedAt).Minutes() <= 1

	fieldsValue["nickname"] = userInfo.Nickname
	fieldsValue["phone"] = userInfo.Phone
	fieldsValue["userId"] = userInfo.ID
	fieldsValue["avatar"] = userInfo.Avatar
	fieldsValue["TimeNote"] = userInfo.Avatar
	fieldsValue["IsSurgery"] = userInfo.IsSurgery
	fieldsValue["HospitalId"] = userInfo.HospitalId
	fieldsValue["IsInfo"] = userInfo.IsInfo
	fieldsValue["SurgeryTime"] = userInfo.SurgeryTime
	fieldsValue["HospitalId"] = userInfo.HospitalId
	fieldsValue["IsSurgery"] = userInfo.IsSurgery

	return
}

// ResponseToken 返回Token生成结果
func ResponseToken(w http.ResponseWriter, data map[string]any, header http.Header, statusCode ...int) error {
	log.Debugf("返回Token原始数据: %+v", data)
	type response struct {
		Code int            `json:"code"`
		Data map[string]any `json:"data"`
		Msg  string         `json:"message"`
	}

	status := http.StatusOK
	msg := "login success"
	if len(statusCode) > 0 && statusCode[0] > 0 {
		status = statusCode[0]
		msg = fmt.Sprintf("%v", data["error_description"])
		// 处理特殊返回 - 刷新Token到期了
		switch data["error"] {
		case "invalid_grant":
			msg = "登录已过期，请重新授权登录"
		case "invalid_request":
			msg = "登录参数错误"
		default:
			log.Errorf("收到未定义的登录错误: %v", data["error_description"])
		}
		data = nil
	}

	res := response{
		Code: status,
		Msg:  msg,
		Data: data,
	}

	jsonBytes, err := json.Marshal(res)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "application/json;charset=UTF-8")
	w.Header().Set("Cache-Control", "no-store")
	w.Header().Set("Pragma", "no-cache")

	for key := range header {
		w.Header().Set(key, header.Get(key))
	}

	w.WriteHeader(status)
	_, err = w.Write(jsonBytes)
	if err != nil {
		log.Errorf("返回Token失败: %v", err.Error())
		return err
	}
	return err
}

// InternalErrorHandler 自定义内部错误处理
func InternalErrorHandler(err error) (re *errors.Response) {
	re = errors.NewResponse(err, http.StatusUnauthorized)
	re.Description = err.Error()
	return
}
