package oauth2

import (
	"git.echol.cn/loser/logger/log"
	"github.com/go-oauth2/oauth2/v4"
	"github.com/go-oauth2/oauth2/v4/manage"
	"github.com/go-oauth2/oauth2/v4/models"
	"github.com/go-oauth2/oauth2/v4/server"
	"github.com/go-oauth2/oauth2/v4/store"
	od "github.com/go-oauth2/redis/v4"
	"miniapp/client"
	"miniapp/model/app"
	"miniapp/model/common/constant"
	"miniapp/oauth2/handle"
	"miniapp/service"
	"time"
)

var OAuthServer *server.Server // Oauth服务

// InitOAuth2Server 初始化OAuth2服务端
func InitOAuth2Server() {
	manager := manage.NewDefaultManager()
	// 配置信息
	cfg := &manage.Config{
		AccessTokenExp:    time.Hour * 3,      // 访问令牌过期时间，三小时
		RefreshTokenExp:   time.Hour * 24 * 7, // 更新令牌过期时间，一周
		IsGenerateRefresh: true,               // 是否生成新的更新令牌
	}
	// 设置密码模式的配置参数
	manager.SetPasswordTokenCfg(cfg)

	manager.MapTokenStorage(od.NewRedisStoreWithCli(client.Redis, constant.OAuth2RedisKey))
	// 生成Token方式
	manager.MapAccessGenerate(handle.NewAccessGenerate())

	// 配置客户端
	clientStore := store.NewClientStore()
	// 从数据库查询所有client信息
	var clients []app.OAuth2Client
	if err := service.ServiceGroupApp.AppServiceGroup.Oauth2ClientService.FinAll(&clients); err != nil {
		log.Panicf("OAuth2服务启动失败[Client信息拉取失败]: %v", err.Error())
	}
	if len(clients) == 0 {
		log.Panic("未配置OAuth2客户端信息")
	}
	// 组装数据
	for _, c := range clients {
		_ = clientStore.Set(c.ClientId, &models.Client{
			ID:     c.ClientId,
			Secret: c.ClientSecret,
		})
	}
	log.Debug("客户端信息初始化完成")
	manager.MapClientStorage(clientStore)

	srv := server.NewServer(server.NewConfig(), manager)
	// 设置密码登录模式处理逻辑
	srv.SetPasswordAuthorizationHandler(handle.LoginWithPassword)
	// 允许密码模式、刷新Token
	srv.SetAllowedGrantType(oauth2.PasswordCredentials, oauth2.Refreshing)
	// 客户端ID和授权模式检查
	srv.SetClientAuthorizedHandler(handle.CheckClient)
	// 自定义响应Token的扩展字段
	srv.SetExtensionFieldsHandler(handle.ExtensionFields)
	// 自定义返回数据接口
	srv.SetResponseTokenHandler(handle.ResponseToken)
	// 自定义内部错误处理
	srv.SetInternalErrorHandler(handle.InternalErrorHandler)
	// 响应错误处理(支持自定义URI及错误明细)
	//srv.SetResponseErrorHandler(handle.ResponseErrorHandler)
	// 自定义解析用户Id函数
	srv.SetUserAuthorizationHandler(handle.UserAuthorizationHandler)

	OAuthServer = srv
}
