package service

import (
	"jaecoo-be/app/database/entity"
	"jaecoo-be/app/module/activity_logs/mapper"
	"jaecoo-be/app/module/activity_logs/repository"
	"jaecoo-be/app/module/activity_logs/request"
	"jaecoo-be/app/module/activity_logs/response"
	"jaecoo-be/app/module/articles/service"
	usersRepository "jaecoo-be/app/module/users/repository"
	"jaecoo-be/utils/paginator"
	utilSvc "jaecoo-be/utils/service"

	"github.com/rs/zerolog"
)

// ActivityLogsService
type activityLogsService struct {
	Repo           repository.ActivityLogsRepository
	UsersRepo      usersRepository.UsersRepository
	ArticleService service.ArticlesService
	Log            zerolog.Logger
}

// ActivityLogsService define interface of IActivityLogsService
type ActivityLogsService interface {
	All(req request.ActivityLogsQueryRequest) (activityLogs []*response.ActivityLogsResponse, paging paginator.Pagination, err error)
	Show(id uint) (activityLogs *response.ActivityLogsResponse, err error)
	Save(req request.ActivityLogsCreateRequest, authToken *string) (activityLogs *entity.ActivityLogs, err error)
	Update(id uint, req request.ActivityLogsUpdateRequest) (err error)
	Delete(id uint) error
	GetActivityStats() (activityStats *response.ActivityStatsResponse, err error)
}

// NewActivityLogsService init ActivityLogsService
func NewActivityLogsService(repo repository.ActivityLogsRepository, log zerolog.Logger, usersRepo usersRepository.UsersRepository, articleService service.ArticlesService) ActivityLogsService {

	return &activityLogsService{
		Repo:           repo,
		Log:            log,
		UsersRepo:      usersRepo,
		ArticleService: articleService,
	}
}

// All implement interface of ActivityLogsService
func (_i *activityLogsService) All(req request.ActivityLogsQueryRequest) (activityLogss []*response.ActivityLogsResponse, paging paginator.Pagination, err error) {
	results, paging, err := _i.Repo.GetAll(req)
	if err != nil {
		return
	}

	for _, result := range results {
		activityLogss = append(activityLogss, mapper.ActivityLogsResponseMapper(result))
	}

	return
}

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

	return mapper.ActivityLogsResponseMapper(result), nil
}

func (_i *activityLogsService) Save(req request.ActivityLogsCreateRequest, authToken *string) (activityLogs *entity.ActivityLogs, err error) {
	_i.Log.Info().Interface("data", req).Msg("")

	newReq := req.ToEntity()

	if authToken != nil {
		createdBy := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, *authToken)
		newReq.UserId = &createdBy.ID
	}

	result, err := _i.Repo.Create(newReq)
	if err != nil {
		return nil, err
	}

	// update article
	err = _i.ArticleService.UpdateActivityCount(*req.ArticleId, req.ActivityTypeId)
	if err != nil {
		return nil, err
	}

	return result, nil
}

func (_i *activityLogsService) Update(id uint, req request.ActivityLogsUpdateRequest) (err error) {
	_i.Log.Info().Interface("data", req).Msg("")
	newReq := req.ToEntity()
	return _i.Repo.Update(id, newReq)
}

func (_i *activityLogsService) Delete(id uint) error {
	return _i.Repo.Delete(id)
}

func (_i *activityLogsService) GetActivityStats() (activityStats *response.ActivityStatsResponse, err error) {
	_i.Log.Info().Interface("GetActivityStats", "checker").Msg("")
	countUniqueVisitorAllTime, err := _i.Repo.CountUniqueVisitorAllTime()
	if err != nil {
		return nil, err
	}
	countUniqueVisitorToday, err := _i.Repo.CountUniqueVisitorToday()
	if err != nil {
		return nil, err
	}
	countTotalViewAllTime, err := _i.Repo.CountTotalViewAllTime()
	if err != nil {
		return nil, err
	}

	getActivityStats := &response.ActivityStatsResponse{
		TotalVisitorAllTime: countUniqueVisitorAllTime,
		TotalVisitorToday:   countUniqueVisitorToday,
		TotalViewAllTime:    countTotalViewAllTime,
	}
	return getActivityStats, nil
}
