package auth

import (
	"context"
	"git.noahlan.cn/n-admin/n-admin-server/api/internal/svc"
	"git.noahlan.cn/n-admin/n-admin-server/api/internal/types"
	"git.noahlan.cn/n-admin/n-admin-server/dal"
	"git.noahlan.cn/n-admin/n-admin-server/dal/errx"
	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/types/core"
	"git.noahlan.cn/noahlan/ntool-biz/core/jwt"
	"git.noahlan.cn/noahlan/ntool-biz/core/nstatus"
	"git.noahlan.cn/noahlan/ntool/ndef"
	"git.noahlan.cn/noahlan/ntool/nlog"
	"net/http"
	"strings"
)

// login 登录
func login(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request, user *core.UserInfo) (*types.LoginResp, error) {
	defer func() {
		if err := loginRecord(ctx, svcCtx, r, user.ID); err != nil {
			nlog.Errorw("记录登录次数失败", nlog.Field("err", err))
		}
	}()

	rolesBuilder := new(strings.Builder)
	for i, v := range user.Roles {
		rolesBuilder.WriteString(v.Code)
		if i != len(user.Roles)-1 {
			rolesBuilder.WriteString(ndef.CommaStr)
		}
	}

	// TODO 检测账号，1是否开启两步验证(已配置) 2是否需要两步验证(异地登录之类)
	// 生成 token
	token, err := jwt.NewJwtToken(
		svcCtx.Config.Auth.AccessSecret,
		user.ID,
		svcCtx.Config.Auth.AccessExpire,
		jwt.WithRandID(),
		jwt.WithOption(jwt.KeyRoles, rolesBuilder.String()),
	)
	if err != nil {
		return nil, nstatus.NewBizErrWithCode(errx.JwtTokenGenerateErr)
	}

	// TODO 落地Token
	return &types.LoginResp{
		TwoFactorType: "",
		Token: types.LoginTokenInfo{
			UID:         user.ID,
			TokenType:   "Bearer",
			AccessToken: token.AccessToken,
			ExpiresAt:   token.ExpiresAt,
			Scope:       "",
		},
	}, nil
}

// loginRecord 记录登录
func loginRecord(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request, uid int64) error {
	// 记录登录次数
	_, err := svcCtx.CoreRpc.Record(ctx, &core.LoginRecordInfo{
		UserId:          uid,
		LastLoginIpv4:   r.RemoteAddr,
		LastLoginDevice: r.Header.Get(dal.UserDeviceKey),
		LastLoginUa:     r.UserAgent(),
	})
	if err != nil {
		return err
	}
	return nil
}

// register 注册用户
func register(ctx context.Context, svcCtx *svc.ServiceContext, user *core.UserInfo) (*core.UserInfo, error) {
	// 自动注册
	rpcResp, err := svcCtx.CoreRpc.CreateUser(ctx, user)
	if err != nil {
		return nil, err
	}
	dbData, err := svcCtx.CoreRpc.GetUser(ctx, &core.UserReq{
		ID: rpcResp.ID,
	})
	if err != nil {
		return nil, err
	}
	return dbData, nil
}
