package service

import (
	"errors"
	approvalHistoriesService "jaecoo-be/app/module/approval_histories/service"
	"jaecoo-be/app/module/galleries/mapper"
	"jaecoo-be/app/module/galleries/repository"
	"jaecoo-be/app/module/galleries/request"
	"jaecoo-be/app/module/galleries/response"
	usersRepository "jaecoo-be/app/module/users/repository"
	"jaecoo-be/config/config"
	"jaecoo-be/utils/paginator"
	utilSvc "jaecoo-be/utils/service"

	"github.com/rs/zerolog"
)

type galleriesService struct {
	Repo                    repository.GalleriesRepository
	Log                     zerolog.Logger
	Cfg                     *config.Config
	UsersRepo               usersRepository.UsersRepository
	ApprovalHistoriesService approvalHistoriesService.ApprovalHistoriesService
}

type GalleriesService interface {
	GetAll(req request.GalleriesQueryRequest) (galleries []*response.GalleriesResponse, paging paginator.Pagination, err error)
	GetOne(id uint) (gallery *response.GalleriesResponse, err error)
	Create(req request.GalleriesCreateRequest) (gallery *response.GalleriesResponse, err error)
	Update(id uint, req request.GalleriesUpdateRequest) (gallery *response.GalleriesResponse, err error)
	Delete(id uint) (err error)
	Approve(id uint, authToken string) (gallery *response.GalleriesResponse, err error)
	Reject(id uint, authToken string, message *string) (gallery *response.GalleriesResponse, err error)
}

func NewGalleriesService(repo repository.GalleriesRepository, log zerolog.Logger, cfg *config.Config, usersRepo usersRepository.UsersRepository, approvalHistoriesService approvalHistoriesService.ApprovalHistoriesService) GalleriesService {
	return &galleriesService{
		Repo:                    repo,
		Log:                     log,
		Cfg:                     cfg,
		UsersRepo:               usersRepo,
		ApprovalHistoriesService: approvalHistoriesService,
	}
}

func (_i *galleriesService) GetAll(req request.GalleriesQueryRequest) (galleries []*response.GalleriesResponse, paging paginator.Pagination, err error) {
	galleriesEntity, paging, err := _i.Repo.GetAll(req)
	if err != nil {
		return
	}

	host := _i.Cfg.App.Domain

	for _, gallery := range galleriesEntity {
		galleries = append(galleries, mapper.GalleriesResponseMapper(gallery, host))
	}

	return
}

func (_i *galleriesService) GetOne(id uint) (gallery *response.GalleriesResponse, err error) {
	galleryEntity, err := _i.Repo.FindOne(id)
	if err != nil {
		return
	}

	if galleryEntity == nil {
		err = errors.New("gallery not found")
		return
	}

	host := _i.Cfg.App.Domain

	gallery = mapper.GalleriesResponseMapper(galleryEntity, host)
	return
}

func (_i *galleriesService) Create(req request.GalleriesCreateRequest) (gallery *response.GalleriesResponse, err error) {
	galleryEntity := req.ToEntity()
	isActive := true
	galleryEntity.IsActive = &isActive

	galleryEntity, err = _i.Repo.Create(galleryEntity)
	if err != nil {
		return
	}

	host := _i.Cfg.App.Domain

	gallery = mapper.GalleriesResponseMapper(galleryEntity, host)
	return
}

func (_i *galleriesService) Update(id uint, req request.GalleriesUpdateRequest) (gallery *response.GalleriesResponse, err error) {
	galleryEntity := req.ToEntity()

	err = _i.Repo.Update(id, galleryEntity)
	if err != nil {
		return
	}

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

	host := _i.Cfg.App.Domain

	gallery = mapper.GalleriesResponseMapper(galleryEntity, host)
	return
}

func (_i *galleriesService) Delete(id uint) (err error) {
	err = _i.Repo.Delete(id)
	return
}

func (_i *galleriesService) Approve(id uint, authToken string) (gallery *response.GalleriesResponse, err error) {
	// Get user from token
	user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
	if user == nil {
		err = errors.New("unauthorized: user not found")
		return
	}

	// Check if user has admin role (roleId = 1)
	if user.UserRoleId != 1 {
		err = errors.New("unauthorized: only admin can approve")
		return
	}

	// Approve gallery (update status_id to 2)
	err = _i.Repo.Approve(id)
	if err != nil {
		return
	}

	// Save approval history
	userID := user.ID
	err = _i.ApprovalHistoriesService.CreateHistory("galleries", id, 2, "approve", &userID, nil)
	if err != nil {
		_i.Log.Error().Err(err).Msg("Failed to save approval history")
	}

	// Get updated gallery data
	galleryEntity, err := _i.Repo.FindOne(id)
	if err != nil {
		return
	}

	if galleryEntity == nil {
		err = errors.New("gallery not found")
		return
	}

	host := _i.Cfg.App.Domain
	gallery = mapper.GalleriesResponseMapper(galleryEntity, host)
	return
}

func (_i *galleriesService) Reject(id uint, authToken string, message *string) (gallery *response.GalleriesResponse, err error) {
	// Get user from token
	user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
	if user == nil {
		err = errors.New("unauthorized: user not found")
		return
	}

	// Check if user has admin role (roleId = 1)
	if user.UserRoleId != 1 {
		err = errors.New("unauthorized: only admin can reject")
		return
	}

	// Reject gallery (update status_id to 3)
	err = _i.Repo.Reject(id)
	if err != nil {
		return
	}

	// Save rejection history
	userID := user.ID
	err = _i.ApprovalHistoriesService.CreateHistory("galleries", id, 3, "reject", &userID, message)
	if err != nil {
		_i.Log.Error().Err(err).Msg("Failed to save rejection history")
	}

	// Get updated gallery data
	galleryEntity, err := _i.Repo.FindOne(id)
	if err != nil {
		return
	}

	if galleryEntity == nil {
		err = errors.New("gallery not found")
		return
	}

	host := _i.Cfg.App.Domain
	gallery = mapper.GalleriesResponseMapper(galleryEntity, host)
	return
}
