package service

import (
	"github.com/google/uuid"
	"github.com/rs/zerolog"
	"web-qudo-be/app/database/entity"
	"web-qudo-be/app/module/activity_logs/mapper"
	"web-qudo-be/app/module/activity_logs/repository"
	"web-qudo-be/app/module/activity_logs/request"
	"web-qudo-be/app/module/activity_logs/response"
	"web-qudo-be/app/module/articles/service"
	usersRepository "web-qudo-be/app/module/users/repository"
	"web-qudo-be/utils/paginator"
	utilSvc "web-qudo-be/utils/service"
)

// 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(clientId *uuid.UUID, req request.ActivityLogsQueryRequest) (activityLogs []*response.ActivityLogsResponse, paging paginator.Pagination, err error)
	Show(clientId *uuid.UUID, id uint) (activityLogs *response.ActivityLogsResponse, err error)
	Save(clientId *uuid.UUID, req request.ActivityLogsCreateRequest, authToken *string) (activityLogs *entity.ActivityLogs, err error)
	Update(clientId *uuid.UUID, id uint, req request.ActivityLogsUpdateRequest) (err error)
	Delete(clientId *uuid.UUID, id uint) error
	GetActivityStats(clientId *uuid.UUID) (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(clientId *uuid.UUID, req request.ActivityLogsQueryRequest) (activityLogss []*response.ActivityLogsResponse, paging paginator.Pagination, err error) {
	results, paging, err := _i.Repo.GetAll(clientId, req)
	if err != nil {
		return
	}

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

	return
}

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

	return mapper.ActivityLogsResponseMapper(result), nil
}

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

	newReq := req.ToEntity()

	if clientId != nil {
		newReq.ClientId = clientId
	}

	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(clientId, *req.ArticleId, req.ActivityTypeId)
	if err != nil {
		return nil, err
	}

	return result, nil
}

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

func (_i *activityLogsService) Delete(clientId *uuid.UUID, id uint) error {
	return _i.Repo.Delete(clientId, id)
}

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

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