package org.xcolab.service.members.service.messaging;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.xcolab.model.tables.pojos.MessagingUserPreferences;
import org.xcolab.service.members.domain.messaging.MessageDao;
import org.xcolab.service.members.service.role.RoleService;

import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * Class responsible for handling verification if user is allowed to send
 * messages or maybe daily limit has been reached.
 * 
 * @author janusz
 */
@Service
public class MessageLimitManager {

    private static final Map<Long, Object> mutexes = new HashMap<>();
	private static final int MESSAGES_DAILY_LIMIT = 15;
	private static final Map<Long, LocalDateTime> lastValidationDateMap = new HashMap<>();

    private final MessagingUserPreferencesService messagingUserPreferencesService;
    private final MessageDao messageDao;
    private final RoleService roleService;

    @Autowired
    private MessageLimitManager(MessagingUserPreferencesService messagingUserPreferencesService,
            MessageDao messageDao, RoleService roleService) {
        this.messagingUserPreferencesService = messagingUserPreferencesService;
        this.messageDao = messageDao;
        this.roleService = roleService;
    }

    /**
     * Method responsible for checking if user is allowed to send given number
     * of messages.
     * 
     * @param messagesToSend
     *            number of messages that user wants to send
     */
    public boolean canSendMessages(int messagesToSend, long memberId) {
        synchronized (getMutex(memberId)) {

            int messageLimit = getMessageLimit(memberId);

            final Timestamp yesterday = Timestamp.from(Instant.now().minus(Duration.ofDays(1)));

            long count = messageDao.countByGiven(memberId, null, null, null, yesterday);

            return messageLimit >= count + messagesToSend;
        }
    }

    public int getNumberOfMessagesLeft(long memberId) {
        int messageLimit = getMessageLimit(memberId);

        final Timestamp yesterday = Timestamp.from(Instant.now().minus(Duration.ofDays(1)));

        int count = messageDao.countByGiven(memberId, null, null, null, yesterday);

        return  messageLimit - count;
    }

    public int getMessageLimit(long memberId) {
        if (roleService.isAdmin(memberId)) {
            return Integer.MAX_VALUE;
        }

        MessagingUserPreferences messagingPreferences = messagingUserPreferencesService.getByMemberId(memberId);

        int messagesLimit;
        if (messagingPreferences.getDailyMessageLimit() != null) {
            messagesLimit = messagingPreferences.getDailyMessageLimit();
        } else {
            messagesLimit = MESSAGES_DAILY_LIMIT;
        }
        return messagesLimit;
    }

    public synchronized Object getMutex(long senderId) {
        return mutexes.computeIfAbsent(senderId, k -> new Object());
    }

	public boolean wasReportedRecently(Long memberId) {
        final LocalDateTime lastEmailSendDate = lastValidationDateMap.get(memberId);

        final LocalDateTime now = LocalDateTime.now();
        if (lastEmailSendDate == null || lastEmailSendDate.plusHours(24).isBefore(now)) {
            lastValidationDateMap.put(memberId, now);
            return false;
        } else {
            return true;
        }
	}
}

@@ -198,38 +198,142 @@
 pojos.Me
-ssagingUserPreferences
+mber;%0Aimport org.xcolab.model.tables.pojos.MessagingUserPreferences;%0Aimport org.xcolab.service.members.domain.member.MemberDao
 ;%0Aimport
@@ -562,16 +562,54 @@
 teTime;%0A
+import java.time.temporal.ChronoUnit;%0A
 import j
@@ -919,17 +919,20 @@
 ap%3C%3E();%0A
-%09
+    
 private 
@@ -975,16 +975,82 @@
 T = 15;%0A
+    private static final int MESSAGES_DAILY_LIMIT_FIRST_DAYS = 2;%0A
 %09private
@@ -1296,16 +1296,55 @@
 Service;
+%0A    private final MemberDao memberDao;
 %0A%0A    @A
@@ -1507,16 +1507,37 @@
 eService
+, MemberDao memberDao
 ) %7B%0A    
@@ -1686,24 +1686,60 @@
 oleService;%0A
+        this.memberDao = memberDao;%0A
     %7D%0A%0A    /
@@ -3177,84 +3177,647 @@
     
-messagesLimit = MESSAGES_DAILY_LIMIT;%0A        %7D%0A        return messagesLimit
+final Member member = memberDao.getMember(memberId)%0A                    .orElseThrow(() -%3E new IllegalStateException(%22Can't check limit for member %22%0A                            + memberId + %22: member does not exist%22));%0A%0A            if (isMoreThan2DaysOld(member)) %7B%0A                messagesLimit = MESSAGES_DAILY_LIMIT;%0A            %7D else %7B%0A                messagesLimit = MESSAGES_DAILY_LIMIT_FIRST_DAYS;;%0A            %7D%0A        %7D%0A        return messagesLimit;%0A    %7D%0A%0A    private boolean isMoreThan2DaysOld(Member member) %7B%0A        return member.getCreateDate().toInstant()%0A                .plus(2, ChronoUnit.DAYS).isBefore(Instant.now())
 ;%0A  

Decrease message limit for new users