package cz.muni.fi.pa165.soccermanager.service.impl;

import cz.muni.fi.pa165.soccermanager.dto.ChampionshipDto;
import cz.muni.fi.pa165.soccermanager.dto.request.CreateChampionshipRequest;
import cz.muni.fi.pa165.soccermanager.exception.NameAlreadyExistsException;
import cz.muni.fi.pa165.soccermanager.mapper.ChampionshipMapper;
import cz.muni.fi.pa165.soccermanager.repository.ChampionshipRepository;
import cz.muni.fi.pa165.soccermanager.service.ChampionshipService;
import java.util.Optional;
import javax.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author Stanislav Koshchienko (uco: 506549)
 */
@Service
@Transactional
@RequiredArgsConstructor
public class ChampionshipServiceImpl implements ChampionshipService {

    private final ChampionshipRepository championshipRepository;

    private final ChampionshipMapper championshipMapper;

    @Override
    @PreAuthorize("hasAuthority('SCOPE_ADMIN')")
    public Long createChampionship(CreateChampionshipRequest request) {
        if (championshipRepository.championshipNameExists(request.getName()).equals(Boolean.TRUE)) {
            throw new NameAlreadyExistsException("Name of championship must be unique");
        }
        return championshipRepository.saveAndFlush(championshipMapper.map(request)).getId();
    }

    @Override
    @Transactional(readOnly = true)
    @PreAuthorize("hasAnyAuthority('SCOPE_USER', 'SCOPE_ADMIN')")
    public Optional<ChampionshipDto> findChampionshipById(Long id) {
        return championshipRepository.findById(id).map(championshipMapper::map);
    }

    @Override
    @PreAuthorize("hasAuthority('SCOPE_ADMIN')")
    public void update(Long id, ChampionshipDto dto) {
        final var c = championshipRepository.findById(id).orElseThrow(() -> {
            throw new EntityNotFoundException();
        });
        championshipMapper.mapOnUpdate(c, dto);
    }

    @Override
    @PreAuthorize("hasAuthority('SCOPE_ADMIN')")
    public void remove(Long id) {
        championshipRepository.delete(championshipRepository.findById(id).orElseThrow(() -> {
            throw new EntityNotFoundException();
        }));
    }

    @Override
    @Transactional(readOnly = true)
    @PreAuthorize("hasAnyAuthority('SCOPE_USER', 'SCOPE_ADMIN')")
    public Page<ChampionshipDto> getAllChampionships(int offset, int pageSize, String field) {
        return championshipRepository
            .findAll(PageRequest.of(offset, pageSize). withSort(Sort.by(field).descending())).map(championshipMapper::map);
    }
}
