package api

import (
	"Gwen/global"
	"Gwen/http/request/api"
	"Gwen/http/response"
	apiResp "Gwen/http/response/api"
	"Gwen/model"
	"Gwen/service"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"strings"
)

type Oauth struct {
}

// OidcAuth
// @Tags Oauth
// @Summary OidcAuth
// @Description OidcAuth
// @Accept  json
// @Produce  json
// @Success 200 {object} apiResp.LoginRes
// @Failure 500 {object} response.ErrorResponse
// @Router /oidc/auth [post]
func (o *Oauth) OidcAuth(c *gin.Context) {
	f := &api.OidcAuthRequest{}
	err := c.ShouldBindJSON(&f)
	if err != nil {
		response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
		return
	}
	//fmt.Println(f)
	if f.Op != model.OauthTypeWebauth && f.Op != model.OauthTypeGoogle && f.Op != model.OauthTypeGithub && f.Op != model.OauthTypeOidc {
		response.Error(c, response.TranslateMsg(c, "ParamsError"))
		return
	}

	err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
	if err != nil {
		response.Error(c, response.TranslateMsg(c, err.Error()))
		return
	}

	service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
		Action:     service.OauthActionTypeLogin,
		Id:         f.Id,
		Op:         f.Op,
		Uuid:       f.Uuid,
		DeviceName: f.DeviceInfo.Name,
		DeviceOs:   f.DeviceInfo.Os,
		DeviceType: f.DeviceInfo.Type,
	}, 5*60)
	//fmt.Println("code url", code, url)
	c.JSON(http.StatusOK, gin.H{
		"code": code,
		"url":  url,
	})
}

func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken) {
	var u *model.User
	var ut *model.UserToken
	q := &api.OidcAuthQuery{}

	// 解析查询参数并处理错误
	if err := c.ShouldBindQuery(q); err != nil {
		response.Error(c, response.TranslateMsg(c, "ParamsError")+": "+err.Error())
		return nil, nil
	}

	// 获取 OAuth 缓存
	v := service.AllService.OauthService.GetOauthCache(q.Code)
	if v == nil {
		response.Error(c, response.TranslateMsg(c, "OauthExpired"))
		return nil, nil
	}

	// 如果 UserId 为 0，说明还在授权中
	if v.UserId == 0 {
		c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind"})
		return nil, nil
	}

	// 获取用户信息
	u = service.AllService.UserService.InfoById(v.UserId)
	if u == nil {
		response.Error(c, response.TranslateMsg(c, "UserNotFound"))
		return nil, nil
	}

	// 删除 OAuth 缓存
	service.AllService.OauthService.DeleteOauthCache(q.Code)

	// 创建登录日志并生成用户令牌
	ut = service.AllService.UserService.Login(u, &model.LoginLog{
		UserId:   u.Id,
		Client:   v.DeviceType,
		Uuid:     v.Uuid,
		Ip:       c.ClientIP(),
		Type:     model.LoginLogTypeOauth,
		Platform: v.DeviceOs,
	})

	if ut == nil {
		response.Error(c, response.TranslateMsg(c, "LoginFailed"))
		return nil, nil
	}

	// 返回用户令牌
	return u, ut
}

// OidcAuthQuery
// @Tags Oauth
// @Summary OidcAuthQuery
// @Description OidcAuthQuery
// @Accept  json
// @Produce  json
// @Success 200 {object} apiResp.LoginRes
// @Failure 500 {object} response.ErrorResponse
// @Router /oidc/auth-query [get]
func (o *Oauth) OidcAuthQuery(c *gin.Context) {
	u, ut := o.OidcAuthQueryPre(c)
	if u == nil || ut == nil {
		return
	}
	c.JSON(http.StatusOK, apiResp.LoginRes{
		AccessToken: ut.Token,
		Type:        "access_token",
		User:        *(&apiResp.UserPayload{}).FromUser(u),
	})
}

// OauthCallback 回调
// @Tags Oauth
// @Summary OauthCallback
// @Description OauthCallback
// @Accept  json
// @Produce  json
// @Success 200 {object} apiResp.LoginRes
// @Failure 500 {object} response.ErrorResponse
// @Router /oauth/callback [get]
func (o *Oauth) OauthCallback(c *gin.Context) {
	state := c.Query("state")
	if state == "" {
		c.String(http.StatusInternalServerError, response.TranslateParamMsg(c, "ParamIsEmpty", "state"))
		return
	}

	cacheKey := state
	//从缓存中获取
	v := service.AllService.OauthService.GetOauthCache(cacheKey)
	if v == nil {
		c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthExpired"))
		return
	}

	ty := v.Op
	ac := v.Action
	var u *model.User
	openid := ""
	thirdName := ""
	//fmt.Println("ty ac ", ty, ac)

	if ty == model.OauthTypeGithub {
		code := c.Query("code")
		err, userData := service.AllService.OauthService.GithubCallback(code)
		if err != nil {
			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
			return
		}
		openid = strconv.Itoa(userData.Id)
		thirdName = userData.Login
	} else if ty == model.OauthTypeGoogle {
		code := c.Query("code")
		err, userData := service.AllService.OauthService.GoogleCallback(code)
		if err != nil {
			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
			return
		}
		openid = userData.Email
		//将空格替换成_
		thirdName = strings.Replace(userData.Name, " ", "_", -1)
	} else if ty == model.OauthTypeOidc {
		code := c.Query("code")
		err, userData := service.AllService.OauthService.OidcCallback(code)
		if err != nil {
			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
			return
		}
		openid = userData.Sub
		thirdName = userData.PreferredUsername
	} else {
		c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
		return
	}
	if ac == service.OauthActionTypeBind {

		//fmt.Println("bind", ty, userData)
		utr := service.AllService.OauthService.UserThirdInfo(ty, openid)
		if utr.UserId > 0 {
			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
			return
		}
		//绑定
		u = service.AllService.UserService.InfoById(v.UserId)
		if u == nil {
			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
			return
		}
		//绑定
		err := service.AllService.OauthService.BindOauthUser(ty, openid, thirdName, v.UserId)
		if err != nil {
			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
			return
		}
		c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
		return

	} else if ac == service.OauthActionTypeLogin {
		//登录
		if v.UserId != 0 {
			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
			return
		}
		u = service.AllService.UserService.InfoByGithubId(openid)
		if u == nil {
			oa := service.AllService.OauthService.InfoByOp(ty)
			if !*oa.AutoRegister {
				//c.String(http.StatusInternalServerError, "还未绑定用户，请先绑定")
				v.ThirdName = thirdName
				v.ThirdOpenId = openid
				url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
				c.Redirect(http.StatusFound, url)
				return
			}

			//自动注册
			u = service.AllService.UserService.RegisterByOauth(ty, thirdName, openid)
			if u.Id == 0 {
				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
				return
			}
		}
		v.UserId = u.Id
		service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
		// 如果是webadmin，登录成功后跳转到webadmin
		if v.DeviceType == "webadmin" {
			/*service.AllService.UserService.Login(u, &model.LoginLog{
				UserId:   u.Id,
				Client:   "webadmin",
				Uuid:     "", //must be empty
				Ip:       c.ClientIP(),
				Type:     model.LoginLogTypeOauth,
				Platform: v.DeviceOs,
			})*/
			url := global.Config.Rustdesk.ApiServer + "/_admin/#/"
			c.Redirect(http.StatusFound, url)
			return
		}
		c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
		return
	} else {
		c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
		return
	}

}
