package service

import (
	"github.com/Nerzal/gocloak/v13"
	"github.com/rs/zerolog"
	"go-humas-be/app/module/users/mapper"
	"go-humas-be/app/module/users/repository"
	"go-humas-be/app/module/users/request"
	"go-humas-be/app/module/users/response"
	"go-humas-be/config/config"
	"go-humas-be/utils/paginator"
	utilSvc "go-humas-be/utils/service"
)

// UsersService
type usersService struct {
	Repo     repository.UsersRepository
	Log      zerolog.Logger
	Keycloak *config.KeycloakConfig
}

// UsersService define interface of IUsersService
type UsersService interface {
	All(req request.UsersQueryRequest) (users []*response.UsersResponse, paging paginator.Pagination, err error)
	Show(id uint) (users *response.UsersResponse, err error)
	Save(req request.UsersCreateRequest, authToken string) (err error)
	Login(req request.UserLogin) (res *gocloak.JWT, err error)
	Update(id uint, req request.UsersUpdateRequest) (err error)
	Delete(id uint) error
}

// NewUsersService init UsersService
func NewUsersService(repo repository.UsersRepository, log zerolog.Logger, keycloak *config.KeycloakConfig) UsersService {

	return &usersService{
		Repo:     repo,
		Log:      log,
		Keycloak: keycloak,
	}
}

// All implement interface of UsersService
func (_i *usersService) All(req request.UsersQueryRequest) (users []*response.UsersResponse, paging paginator.Pagination, err error) {
	results, paging, err := _i.Repo.GetAll(req)
	if err != nil {
		return
	}

	for _, result := range results {
		users = append(users, mapper.UsersResponseMapper(result))
	}

	return
}

func (_i *usersService) Show(id uint) (users *response.UsersResponse, err error) {
	result, err := _i.Repo.FindOne(id)
	if err != nil {
		return nil, err
	}

	return mapper.UsersResponseMapper(result), nil
}

func (_i *usersService) Save(req request.UsersCreateRequest, authToken string) (err error) {
	_i.Log.Info().Interface("data", req).Msg("")
	newReq := req.ToEntity()

	createdBy := utilSvc.GetUserInfo(_i.Log, _i.Repo, authToken)
	newReq.CreatedById = &createdBy.ID

	keycloakId, err := _i.Keycloak.CreateUser(req.Fullname, req.Email, req.Username, req.Password)
	if err != nil {
		return err
	}

	newReq.KeycloakId = &keycloakId

	return _i.Repo.Create(newReq)
}

func (_i *usersService) Login(req request.UserLogin) (res *gocloak.JWT, err error) {
	_i.Log.Info().Interface("data", req).Msg("")

	loginResponse, err := _i.Keycloak.Login(req.Username, req.Password)
	if err != nil {
		return nil, err
	}
	return loginResponse, nil
}

func (_i *usersService) Update(id uint, req request.UsersUpdateRequest) (err error) {
	_i.Log.Info().Interface("data", req).Msg("")
	newReq := req.ToEntity()

	findUser, err := _i.Repo.FindOne(id)
	if err != nil {
		return err
	}

	err = _i.Keycloak.UpdateUser(findUser.KeycloakId, req.Fullname, req.Email)
	if err != nil {
		return err
	}

	return _i.Repo.Update(id, newReq)
}

func (_i *usersService) Delete(id uint) error {
	result, err := _i.Repo.FindOne(id)
	if err != nil {
		return err
	}

	isActive := false
	result.IsActive = &isActive
	return _i.Repo.Update(id, result)
}
