package service

import (
	"campaign-pool-be/app/database/entity"
	"campaign-pool-be/app/module/campaigns/mapper"
	"campaign-pool-be/app/module/campaigns/repository"
	"campaign-pool-be/app/module/campaigns/request"
	"campaign-pool-be/app/module/campaigns/response"
	usersRepository "campaign-pool-be/app/module/users/repository"
	config "campaign-pool-be/config/config"
	"campaign-pool-be/utils/paginator"
	utilSvc "campaign-pool-be/utils/service"

	"github.com/rs/zerolog"
)

// CampaignsService
type campaignsService struct {
	Repo      repository.CampaignsRepository
	UsersRepo usersRepository.UsersRepository
	Log       zerolog.Logger
	Cfg       *config.Config
}

// CampaignsService define interface of ICampaignsService
type CampaignsService interface {
	All(req request.CampaignsQueryRequest, authToken string) (campaigns []*response.CampaignsResponse, paging paginator.Pagination, err error)
	Show(id uint) (campaigns *response.CampaignsResponse, err error)
	Save(req request.CampaignsCreateRequest, authToken string) (campaigns *entity.Campaigns, err error)
	Update(id uint, req request.CampaignsUpdateRequest) (err error)
	Delete(id uint) error
}

// NewCampaignsService init CampaignsService
func NewCampaignsService(repo repository.CampaignsRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger, cfg *config.Config) CampaignsService {
	return &campaignsService{
		Repo:      repo,
		UsersRepo: usersRepo,
		Log:       log,
		Cfg:       cfg,
	}
}

// All implement interface of CampaignsService
func (_i *campaignsService) All(req request.CampaignsQueryRequest, authToken string) (campaignss []*response.CampaignsResponse, paging paginator.Pagination, err error) {
	results, paging, err := _i.Repo.GetAll(req)
	if err != nil {
		return
	}

	host := _i.Cfg.App.Domain
	for _, result := range results {
		campaignss = append(campaignss, mapper.CampaignsResponseMapper(result, host))
	}

	return
}

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

	host := _i.Cfg.App.Domain
	return mapper.CampaignsResponseMapper(result, host), nil
}

func (_i *campaignsService) Save(req request.CampaignsCreateRequest, authToken string) (campaigns *entity.Campaigns, err error) {
	_i.Log.Info().Interface("data", req).Msg("")
	newReq := req.ToEntity()

	if req.CreatorID != nil {
		creator, err := _i.UsersRepo.FindOne(*req.CreatorID)
		if err != nil {
			return nil, err
		}
		newReq.CreatorID = creator.ID
	} else {
		creator := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
		if creator != nil {
			newReq.CreatorID = creator.ID
		}
	}

	// Set default status if not provided
	if newReq.Status == "" {
		newReq.Status = "draft"
	}

	return _i.Repo.Create(newReq)
}

func (_i *campaignsService) Update(id uint, req request.CampaignsUpdateRequest) (err error) {
	_i.Log.Info().Interface("data", req).Msg("")

	newReq := req.ToEntity()
	return _i.Repo.Update(id, newReq)
}

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