package eu.dnetlib.openaire.usermanagement.utils;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import eu.dnetlib.openaire.user.pojos.RoleVerification;
import eu.dnetlib.openaire.user.utils.ManagerVerificationActions;
import org.apache.log4j.Logger;
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.Random;


@Component("VerificationUtils")
public class VerificationUtils {

    private final Random random = new Random();
    private static final Logger logger = Logger.getLogger(VerificationUtils.class);

    @Autowired
    private ManagerVerificationActions actions;

    public JsonObject createManagerInvitation(String email, String type, String entity) {
        RoleVerification roleVerification = actions.getManagerVerification(email, type, entity);
        if(roleVerification == null) {
            String id;
            do {
                id = createId();
            } while (exists(id));
            roleVerification = actions.addManagerVerification(id, email, type, entity, createVerificationCode(), new Timestamp(new Date().getTime()));
        }
        JsonObject invitation = new JsonObject();
        invitation.addProperty("link", roleVerification.getId());
        invitation.addProperty("code", roleVerification.getVerificationCode());
        return invitation;
    }

    public JsonObject createMemberInvitation(String email, String type, String entity) {
        String id;
        do {
            id = createId();
        } while (exists(id));
        RoleVerification roleVerification = actions.getMemberVerification(email, type, entity);
        if(roleVerification == null) {
            roleVerification = actions.addMemberVerification(id, email, type, entity, createVerificationCode(), new Timestamp(new Date().getTime()));
        }
        JsonObject invitation = new JsonObject();
        invitation.addProperty("link", roleVerification.getId());
        invitation.addProperty("code", roleVerification.getVerificationCode());
        return invitation;
    }

    public void deleteManagerVerifications(String email, String type, String entity) {
        RoleVerification roleVerification = actions.getManagerVerification(email, type, entity);
        if (roleVerification != null) {
            deleteVerification(roleVerification.getId());
        }
    }

    public void deleteMemberVerifications(String email, String type, String entity) {
        RoleVerification roleVerification = actions.getMemberVerification(email, type, entity);
        if (roleVerification != null) {
            deleteVerification(roleVerification.getId());
        }
    }

    public void deleteVerification(String id) {
        actions.delete(id);
    }

    public JsonArray getInvitedManagers(String type, String id) {
        List<String> emails = actions.getInvitedManagers(type, id);
        JsonArray users = new JsonArray();
        emails.forEach(users::add);
        return users;
    }

    public JsonArray getInvitedMembers(String type, String id) {
        List<String> emails = actions.getInviteMembers(type, id);
        JsonArray users = new JsonArray();
        emails.forEach(users::add);
        return users;
    }

    public RoleVerification getVerification(String id) {
        return actions.get(id);
    }

    public boolean exists(String id) {
        return actions.exists(id);
    }

    public boolean ownedVerification(String id) {
        try {
            RoleVerification managerVerification = getVerification(id);
            if (managerVerification != null) {
                OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
                String email = authentication.getUserInfo().getEmail().toLowerCase();
                return managerVerification.getEmail().toLowerCase().equals(email);
            }
        } catch (Exception e) {
            logger.error("Get User info: An error occurred ", e);
            return false;
        }
        return false;
    }

    private String createId() {
        return random.ints(48, 123)
                .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
                .limit(16)
                .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
                .toString();
    }

    private String createVerificationCode() {
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(9));
        }
        return code.toString();
    }
}
