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

import cz.muni.fi.pa165.soccermanager.dto.PlayerDto;
import cz.muni.fi.pa165.soccermanager.dto.request.CreatePlayerRequest;
import cz.muni.fi.pa165.soccermanager.dto.request.UpdatePlayerDto;
import cz.muni.fi.pa165.soccermanager.mapper.PlayerMapper;
import cz.muni.fi.pa165.soccermanager.repository.PlayerRepository;
import cz.muni.fi.pa165.soccermanager.service.PlayerService;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DataAccessException;
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;

@Service
@Transactional
@RequiredArgsConstructor
public class PlayerServiceImpl implements PlayerService {

    private final PlayerRepository playerRepository;
    private final PlayerMapper playerMapper;

    @Override
    @PreAuthorize("@sc.playerOwnerOrAdmin(#player)")
    public void update(Long player, UpdatePlayerDto playerDTO) {
        final var p = playerRepository.findById(player).orElseThrow(() -> {
            throw new EntityNotFoundException();
        });
        playerMapper.mapOnUpdate(p, playerDTO);
    }

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

    @Override
    @Transactional(readOnly = true)
    @PreAuthorize("hasAnyAuthority('SCOPE_USER', 'SCOPE_ADMIN')")
    public Optional<PlayerDto> findPlayerById(Long playerId) {
        return playerRepository.findById(playerId).map(playerMapper::map);
    }

    @Override
    @PreAuthorize("hasAuthority('SCOPE_ADMIN')")
    public Long savePlayer(CreatePlayerRequest request) {
        return playerRepository.saveAndFlush(playerMapper.map(request)).getId();
    }

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

    @Override
    @PreAuthorize("hasAnyAuthority('SCOPE_USER', 'SCOPE_ADMIN')")
    public List<PlayerDto> findPlayersByTeam(Long team) {
        return playerRepository.findByTeam(team).stream().map(playerMapper::map).collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    @PreAuthorize("hasAnyAuthority('SCOPE_USER', 'SCOPE_ADMIN')")
    public List<PlayerDto> findFreeAgents() {
        return playerRepository.findFreeAgents().stream().map(playerMapper::map).collect(Collectors.toList());
    }
}
