package ru.ulstu.paper.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.file.service.FileService;
import ru.ulstu.paper.model.Paper;
import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.paper.model.PaperStatusDto;
import ru.ulstu.paper.repository.PaperRepository;
import ru.ulstu.user.model.UserDto;
import ru.ulstu.user.service.MailService;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static ru.ulstu.core.util.StreamApiUtils.convert;

@Service
public class PaperService {

    private final PaperRepository paperRepository;
    private final FileService fileService;
    public final MailService mailService;


    public PaperService(PaperRepository paperRepository,
                        FileService fileService, MailService mailService) {
        this.paperRepository = paperRepository;
        this.fileService = fileService;
        this.mailService = mailService;
    }

    public List<PaperDto> findAll() {
        List<Paper> allPapers = paperRepository.findAll();
        allPapers = allPapers.stream().sorted((paper1, paper2) -> {
            int statusCompareResult =
                    Integer.valueOf(Arrays.asList(Paper.PaperStatus.values()).indexOf(paper1.getStatus()))
                            .compareTo(Integer.valueOf(Arrays.asList(Paper.PaperStatus.values()).indexOf(paper2.getStatus())));
            if (statusCompareResult != 0) {
                return statusCompareResult;
            }
            return paper1.getTitle().compareTo(paper2.getTitle());
        }).collect(Collectors.toList());
        return convert(allPapers, PaperDto::new);
    }

    @Transactional
    public int create(PaperDto paperDto) throws IOException {
        return paperRepository.save(copyFromDto(new Paper(), paperDto)).getId();
    }

    private Paper copyFromDto(Paper paper, PaperDto paperDto) throws IOException {
        paper.setComment(paperDto.getComment());
        paper.setCreateDate(paperDto.getCreateDate());
        paper.setLocked(paperDto.getLocked());
        paper.setStatus(paperDto.getStatus());
        paper.setTitle(paperDto.getTitle());
        paper.setUpdateDate(paperDto.getUpdateDate());
        if (paperDto.getTmpFileName() != null) {
            paper.setFileData(fileService.createFileFromTmp(paperDto.getTmpFileName()));
        }
        return paper;
    }

    @Transactional
    public Integer update(PaperDto paperDto) throws IOException {
        Paper paper = paperRepository.findOne(paperDto.getId());
        if(paper != null && paper.getStatus() != paperDto.getStatus()){
            sendMessageAboutStatusChange(paper.getStatus(),paperDto);
        }
        if (paperDto.getTmpFileName() != null && paper.getFileData() != null) {
            fileService.deleteFile(paper.getFileData());
        }
        return paperRepository.save(copyFromDto(paper, paperDto)).getId();
    }

    @Transactional
    public void delete(Integer paperId) throws IOException {
        Paper paper = paperRepository.findOne(paperId);
        if (paper.getFileData() != null) {
            fileService.deleteFile(paper.getFileData());
        }
        paperRepository.delete(paper);
    }

    public List<PaperStatusDto> getPaperStatuses() {
        return convert(Arrays.asList(Paper.PaperStatus.values()), status ->new PaperStatusDto(status));
    }

    private void sendMessageAboutStatusChange(Paper.PaperStatus oldStatus, PaperDto paper){
        for (UserDto user: paper.getAuthors()) {
            mailService.sendEmail(user.getEmail(), "Обновление статуса статьи",
                    "Статус статьи " + paper.getTitle() + " сменился с " + oldStatus.getName()
                            + " на " + paper.getStatus().getName());
        }
    }
}
