package de.thpeetz.kontor.admin;

import de.thpeetz.kontor.admin.data.Permission;
import de.thpeetz.kontor.admin.data.Profile;
import de.thpeetz.kontor.admin.data.Assignment;
import de.thpeetz.kontor.admin.repository.AssignmentRepository;
import de.thpeetz.kontor.admin.repository.ProfileRepository;
import de.thpeetz.kontor.admin.repository.MailAccountRepository;
import de.thpeetz.kontor.admin.services.AdminService;
import de.thpeetz.kontor.mailclient.data.MailAccount;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;

@Slf4j
@Component
public class SetupModuleAdmin implements ApplicationListener<ContextRefreshedEvent> {
    boolean alreadySetup = false;

    @Autowired
    private ProfileRepository profileRepository;

    @Autowired
    private AssignmentRepository assignmentRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private MailAccountRepository mailAccountRepository;

    @Autowired
    private MailProperties mailProperties;

    @Autowired
    private AdminService adminService;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (alreadySetup) {
            return;
        }

        // Create initial roles and users
        Permission adminPermission = adminService.addPermission("ROLE_ADMIN");
        Permission userPermission = adminService.addPermission("ROLE_USER");
        List<Profile> profiles = profileRepository.findAll();
        if (profiles.isEmpty()) {
            Profile adminProfile = initAdminUser();
            initAssignments(adminPermission, adminProfile);
            initAssignments(userPermission, adminProfile);
        }
        log.info("MailProperties: {}", mailProperties);
        initMail(mailProperties);
    }

    private void initMail(MailProperties mailProperties) {
        log.info("initMail: Host {} with User {}", mailProperties.getHost(), mailProperties.getUserName());
        if (mailProperties.getHost() == null || mailProperties.getHost().isEmpty()) {
            return;
        }
        boolean addMailAccount = false;
        List<MailAccount> mailAccounts = mailAccountRepository.findAll();
        if (mailAccounts.isEmpty()) {
            addMailAccount = true;
        }
        for (MailAccount mailAccount : mailAccounts) {
            String accountUser = mailAccount.getUserName();
            String propertyUser = mailProperties.getUserName();
            String accountHost = mailAccount.getHost();
            String propertyHost = mailProperties.getHost();
            if (propertyHost.equals(accountHost) && propertyUser.equals(accountUser)) {
                log.debug("already configured: {}", mailAccount);
            } else {
                addMailAccount = true;
            }
        }
        if (addMailAccount) {
            log.info("add Mail Account: {}", mailProperties);
            MailAccount mailAccount = new MailAccount();
            mailAccount.setProtocol(mailProperties.getProtocol());
            mailAccount.setHost(mailProperties.getHost());
            mailAccount.setPort(mailProperties.getPort());
            mailAccount.setUserName(mailProperties.getUserName());
            mailAccount.setPassword(mailProperties.getPassword());
            mailAccount.setStartTls(mailProperties.getStartTls());
            mailAccountRepository.save(mailAccount);
        }
    }

    private void initAssignments(Permission permission, Profile profile) {
        log.info("initAssignments: Permission {} for Profile {}", permission.getName(), profile.getUserName());
        Collection<Assignment> configuredRoles = assignmentRepository.findByProfile(profile);
        if (configuredRoles.stream().anyMatch(assignment -> assignment.getPermission().getId().equals(permission.getId()))) {
            log.info("Permission {} already defined", permission.getName());
        } else {
            log.info("add Permission {} to Profile {}", permission.getName(), profile.getUserName());
            final Assignment assignment = new Assignment();
            assignment.setProfile(profile);
            assignment.setPermission(permission);
            assignmentRepository.save(assignment);
        }
    }

    private Profile initAdminUser() {
        log.info("initAdminUser");
        Profile admin = profileRepository.findByUserName("admin");
        if (admin == null) {
            log.info("Profile admin not found, will be created.");
            admin = new Profile();
            admin.setFirstName("Admin");
            admin.setLastName("Administrator");
            admin.setUserName("admin");
            admin.setEmail("admin@example.org");
            admin.setPassword(passwordEncoder.encode("admin"));
            profileRepository.save(admin);
        }
        return admin;
    }
}
