package admin

import (
	"context"
	"server/internal/consts"
	"server/internal/dao"
	"server/internal/model"
	"server/internal/model/do"
	"server/internal/model/entity"
	"server/internal/service"
	"server/utility/ecode"
	"server/utility/encrypt"
	"server/utility/jwt"
)

type sAdmin struct{}

func init() {
	service.RegisterAdmin(New())
}

func New() service.IAdmin {
	return &sAdmin{}
}

func (s *sAdmin) Login(ctx context.Context, in *model.AdminLoginIn) (out *model.AdminLoginOut, err error) {
	admin, err := dao.Admins.Ctx(ctx).Where(dao.Admins.Columns().Username, in.Username).One()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}

	if admin.IsEmpty() {
		return nil, ecode.Auth
	}

	if !encrypt.ComparePassword(admin[dao.Admins.Columns().PasswordHash].String(), in.Password) {
		return nil, ecode.Password
	}
	token, err := jwt.GenerateToken(&jwt.TokenIn{
		Role:   consts.AdminRoleCode,
		UserId: admin[dao.Admins.Columns().Id].Int64(),
	})
	if err != nil {
		return nil, ecode.Fail.Sub("token_generation_failed")
	}
	return &model.AdminLoginOut{
		Token: token,
	}, nil
}

func (s *sAdmin) Info(ctx context.Context, in *model.AdminInfoIn) (out *model.AdminInfoOut, err error) {
	exist, err := dao.Admins.Ctx(ctx).WherePri(in.AdminId).Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("admin_query_failed")
	}
	if !exist {
		return nil, ecode.Auth.Sub("admin_not_found")
	}
	var admin entity.Admins
	err = dao.Admins.Ctx(ctx).WherePri(in.AdminId).Scan(&admin)
	if err != nil {
		return nil, ecode.Fail.Sub("admin_query_failed")
	}
	return &model.AdminInfoOut{
		Id:       admin.Id,
		Username: admin.Username,
		Role:     consts.AdminRoleCode,
	}, nil
}

func (s *sAdmin) EditPass(ctx context.Context, in *model.AdminEditPassIn) (out *model.AdminEditPassOut, err error) {
	admin, err := dao.Admins.Ctx(ctx).WherePri(in.AdminId).One()
	if err != nil {
		return nil, ecode.Fail.Sub("admin_query_failed")
	}
	if admin.IsEmpty() {
		return nil, ecode.Auth.Sub("admin_not_found")
	}
	if !encrypt.ComparePassword(admin[dao.Admins.Columns().PasswordHash].String(), in.OldPass) {
		return nil, ecode.Password.Sub("password_incorrect")
	}
	hash, err := encrypt.EncryptPassword(in.NewPass)
	if err != nil {
		return nil, ecode.Fail.Sub("password_encryption_failed")
	}
	_, err = dao.Admins.Ctx(ctx).WherePri(in.AdminId).Data(do.Admins{PasswordHash: hash}).Update()
	if err != nil {
		return nil, ecode.Fail.Sub("password_update_failed")
	}
	return &model.AdminEditPassOut{
		Success: true,
	}, nil
}
