package eu.eudat.logic.services.utilities;


import eu.eudat.data.dao.entities.DMPDao;
import eu.eudat.data.dao.entities.InvitationDao;
import eu.eudat.data.entities.DMP;
import eu.eudat.data.entities.Invitation;
import eu.eudat.data.entities.UserDMP;
import eu.eudat.models.data.invitation.Properties;
import eu.eudat.models.data.mail.SimpleMail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;


@Service("invitationService")
public class InvitationServiceImpl implements InvitationService {
    private static final Logger logger = LoggerFactory.getLogger(InvitationServiceImpl.class);
    private Environment environment;

    @Autowired
    public InvitationServiceImpl(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void assignToDmp(DMPDao dmpDao, List<eu.eudat.data.entities.UserDMP> users, DMP dmp) {
        for (eu.eudat.data.entities.UserDMP user : users) {
            dmp.getUsers().add(user);
        }
        dmpDao.createOrUpdate(dmp);
    }

    @Override
    public void assignToDmp(DMPDao dmpDao, eu.eudat.data.entities.UserDMP user, DMP dmp) {
        if (!dmp.getUsers().stream().map(x -> x.getUser().getId()).collect(Collectors.toList()).contains(user.getId())) {
            dmp.getUsers().add(user);
            dmpDao.createOrUpdate(dmp);
        }
    }

    @Override
    public void createInvitations(InvitationDao invitationDao, MailService mailService, List<eu.eudat.data.entities.UserInfo> users, DMP dmp, Integer role, eu.eudat.data.entities.UserInfo creator) throws MessagingException {
        for (eu.eudat.data.entities.UserInfo userInfo : users) {
            Invitation invitation = new Invitation();
            invitation.setDmp(dmp);
            invitation.setInvitationEmail(userInfo.getEmail());
            invitation.setUser(creator);
            invitation.setToken(UUID.randomUUID());
            invitation.setAcceptedInvitation(false);
            Properties properties = new Properties();
            properties.setRole(role);
            try {
                JAXBContext context = JAXBContext.newInstance(Properties.class);
                Marshaller marshaller = context.createMarshaller();
                StringWriter propertyWriter = new StringWriter();
                marshaller.marshal(properties, propertyWriter);
                invitation.setProperties(propertyWriter.toString());
            }catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            invitationDao.createOrUpdate(invitation);
            sendInvitationAsync(dmp, invitation, userInfo.getName(), mailService, role);
        }
    }

    @Override
    public CompletableFuture sendInvitationAsync(DMP dmp, Invitation invitation, String recipient, MailService mailService, Integer role) {
        return CompletableFuture.runAsync(() -> {
            SimpleMail mail = new SimpleMail();
            mail.setSubject(createSubject(dmp, mailService.getMailTemplateSubject()));
            mail.setContent(createContent(invitation.getId(), dmp, recipient, mailService.getMailTemplateContent(this.environment.getProperty("email.invite")), role));
            mail.setTo(invitation.getInvitationEmail());
            try {
                mailService.sendSimpleMail(mail);
            } catch (Exception ex) {
                logger.error(ex.getMessage(), ex);
            }
        });
    }

    private String createSubject(DMP dmp, String templateSubject) {
        String subject = templateSubject.replace("{dmpname}", dmp.getLabel());
        return subject;
    }

    private String createContent(UUID invitationID, DMP dmp, String recipient, String templateContent, Integer role) {
        String content = templateContent.replace("{dmpname}", dmp.getLabel());
        content = content.replace("{invitationID}", invitationID.toString());
        content = content.replace("{recipient}", recipient);
        content = content.replace("{host}", this.environment.getProperty("dmp.domain"));
        content = content.replace("{dmprole}", UserDMP.UserDMPRoles.fromInteger(role).name());

        return content;
    }
}
