package auth

import (
	"context"
	"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/nstatus"
	"git.noahlan.cn/noahlan/ntool-biz/core/nstatus/msg"
	"git.noahlan.cn/noahlan/ntool/nstd/tea"
	"git.noahlan.cn/noahlan/ntool/nstr"

	"git.noahlan.cn/n-admin/n-admin-server/api/internal/svc"
	"git.noahlan.cn/n-admin/n-admin-server/api/internal/types"

	"net/http"
)

type LoginByCodeLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	r      *http.Request
}

func NewLoginByCodeLogic(r *http.Request, ctx context.Context, svcCtx *svc.ServiceContext) *LoginByCodeLogic {
	return &LoginByCodeLogic{
		r:      r,
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *LoginByCodeLogic) LoginByCode(req *types.LoginReq) (resp *types.LoginResp, err error) {
	if err := l.svcCtx.Captcha.Verify(req.CaptchaId, req.Captcha, true); err != nil {
		return nil, err
	}
	var user *core.UserInfo
	if nstr.IsChineseMobile(req.Subject) {
		// mobile
		user, err = l.getUserByPhone(req.Subject, req.Credentials)
	} else if nstr.IsEmpty(req.Subject) {
		// email
		user, err = l.getUserByEmail(req.Subject, req.Credentials)
	} else {
		return nil, nstatus.NewBizErrWithCode(errx.NeedPhoneOrEmail)
	}
	if err != nil {
		return nil, err
	}

	// 登录
	resp, err = login(l.ctx, l.svcCtx, l.r, user)
	if err != nil {
		return nil, err
	}
	return
}

func (l *LoginByCodeLogic) getUserByPhone(phone, credentials string) (*core.UserInfo, error) {
	// 验证
	code, _, err := l.svcCtx.CodeCache.GetCachedCode(phone, types.CodeSourceSms, types.SmsCodeTypeLogin)
	if err != nil {
		return nil, nstatus.NewApiInternalErr(msg.CacheError)
	}
	if credentials != code {
		return nil, nstatus.NewBizErrWithCode(errx.WrongCode)
	}
	dbData, err := l.svcCtx.CoreRpc.GetUser(l.ctx, &core.UserReq{
		PhoneNumber: phone,
	})
	if err != nil {
		if nstatus.IsNotFound(err) {
			dbData, err = register(l.ctx, l.svcCtx, &core.UserInfo{
				Username:    phone,
				PhoneNumber: &phone,
				Password:    l.svcCtx.Config.RegisterConf.DefaultPassword,
				Nickname:    tea.String("手机用户" + phone),
			})
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}
	return dbData, nil
}

func (l *LoginByCodeLogic) getUserByEmail(subject, credentials string) (*core.UserInfo, error) {
	// 验证
	code, _, err := l.svcCtx.CodeCache.GetCachedCode(subject, types.CodeSourceEmail, types.SmsCodeTypeLogin)
	if err != nil {
		return nil, nstatus.NewApiInternalErr(msg.CacheError)
	}
	if credentials != code {
		return nil, nstatus.NewBizErrWithCode(errx.WrongCode)
	}
	dbData, err := l.svcCtx.CoreRpc.GetUser(l.ctx, &core.UserReq{
		Email: subject,
	})
	if err != nil {
		if nstatus.IsNotFound(err) {
			dbData, err = register(l.ctx, l.svcCtx, &core.UserInfo{
				Username: subject,
				Email:    &subject,
				Password: l.svcCtx.Config.RegisterConf.DefaultPassword,
				Nickname: tea.String("邮箱用户" + subject),
			})
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}
	return dbData, nil
}
