package ru.yandex.webmaster3.worker.notifications.sending;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import com.google.common.base.Strings;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.data.WebmasterUser;
import ru.yandex.webmaster3.core.user.UserVerifiedHost;
import ru.yandex.webmaster3.core.util.json.JsonMapping;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskState;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.storage.abt.AbtService;
import ru.yandex.webmaster3.storage.abt.model.Experiment;
import ru.yandex.webmaster3.storage.host.CommonDataState;
import ru.yandex.webmaster3.storage.host.CommonDataType;
import ru.yandex.webmaster3.storage.notifications.EmailTrackingInfo;
import ru.yandex.webmaster3.storage.notifications.service.TrackingEmailSenderService;
import ru.yandex.webmaster3.storage.notifications.service.UserNotificationSettingsService;
import ru.yandex.webmaster3.storage.postpone.PostWelcomeEmailData;
import ru.yandex.webmaster3.storage.postpone.PostponeActionYDao;
import ru.yandex.webmaster3.storage.postpone.PostponeOperationType;
import ru.yandex.webmaster3.storage.settings.dao.CommonDataStateYDao;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;
import ru.yandex.webmaster3.worker.notifications.EuEmailService;
import ru.yandex.webmaster3.worker.notifications.services.PostWelcomeMessageBodyBuilderService;

/**
 * ishalaru
 * 11.03.2020
 **/
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Component("sendPostWelcomeEmailTask")
public class SendPostWelcomeEmailTask extends PeriodicTask<SendPostWelcomeEmailTask.TaskState> {
    public static final String SHORT = "SHORT";
    private final CommonDataStateYDao commonDataStateYDao;
    private final PostponeActionYDao postponeActionYDao;
    private final UserHostsService userHostsService;
    private final PostWelcomeMessageBodyBuilderService postWelcomeMessageBodyBuilderService;
    private final TrackingEmailSenderService trackingEmailSenderService;
    private final UserNotificationSettingsService userNotificationSettingsService;
    private final AbtService abtService;
    private final EuEmailService euEmailService;

    @Override
    public Result run(UUID runId) {
        setState(new TaskState());
        state.map = new HashMap<>();
        final DateTime lastImportDate = getLastImportDate();
        DateTime workDate = validateLastImportDate(lastImportDate);
        if (workDate == null) {
            return Result.SUCCESS;
        }
        state.date = workDate.toString();
        commonDataStateYDao.update(new CommonDataState(CommonDataType.LAST_SEND_POST_WELCOME_EMAIL_SEND_PROCESS, workDate.toString(), new DateTime()));
        postponeActionYDao.loadPostponedData(postponeData -> {
            if (postponeData.getType() == PostponeOperationType.POST_WELCOME_EMAIL &&
                    postponeData.getDate().getMillis() == workDate.getMillis()) {
                state.totalProcessed++;
                final PostWelcomeEmailData postWelcomeEmailData =
                        JsonMapping.readValue(postponeData.getData(), PostWelcomeEmailData.class);
                if (isHaveOnlyOneVerifiedHost(postWelcomeEmailData)) {
                    log.debug("Post welcome message : {}", postWelcomeEmailData);
                    state.sendCount++;
                    sendNotification(postWelcomeEmailData);
                }
                postponeActionYDao.delete(postponeData);
            }
        });
        return Result.SUCCESS;
    }

    private boolean isHaveOnlyOneVerifiedHost(final PostWelcomeEmailData postWelcomeEmailData) {
        final List<UserVerifiedHost> verifiedHosts = userHostsService.getVerifiedHosts(new WebmasterUser(postWelcomeEmailData.getUserId()));
        final Optional<UserVerifiedHost> verifiedHost = verifiedHosts
                .stream()
                .filter(e -> e.getVerificationDate().isAfter(DateTime.now().minusMonths(3)))
                .min(Comparator.comparing(UserVerifiedHost::getVerificationDate));
        return verifiedHost
                .map(e -> e.getWebmasterHostId().equals(postWelcomeEmailData.getHostId()))
                .orElse(Boolean.FALSE);
    }

    private void sendNotification(final PostWelcomeEmailData postWelcomeEmailData) {

        final boolean shortMessage = isShortMessage(postWelcomeEmailData.getHostId());
        MESSAGE_TYPE messageType = MESSAGE_TYPE.LONG_CONTENT;
        if (shortMessage) {
            messageType = MESSAGE_TYPE.SHORT_CONTENT;
        }

        state.map.compute(messageType, (key, val) -> (val == null) ? 1 : val + 1);

        String userEmail = userNotificationSettingsService.getUserEmailOrDefaultIfEmpty(postWelcomeEmailData.getUserId());
        if (userEmail == null) {
            log.error("User:{}, don't have email", postWelcomeEmailData.getUserId());
            return;
        }
        if (!euEmailService.isAddressEuropean(userEmail)) {
            EmailTrackingInfo trackingInfo = new EmailTrackingInfo(postWelcomeEmailData.getHostId(),
                    postWelcomeEmailData.getUserId()
                    , shortMessage ? "POST_WELCOME_SHORT" : "POST_WELCOME_LONG", DateTime.now());
            trackingEmailSenderService.sendEmail(userEmail, "",
                    postWelcomeMessageBodyBuilderService.buildSubject(postWelcomeEmailData, shortMessage),
                    postWelcomeMessageBodyBuilderService.buildBody(postWelcomeEmailData, shortMessage, false),
                    trackingInfo);
        } else {
            state.european++;
        }
    }

    private DateTime getLastImportDate() {
        final CommonDataState value = commonDataStateYDao.getValue(CommonDataType.LAST_SEND_POST_WELCOME_EMAIL_SEND_PROCESS);
        if (value == null) {
            return new DateTime(2019, 12, 01, 0, 0).withTimeAtStartOfDay().toDateTime(DateTimeZone.UTC);
        }
        return DateTime.parse(value.getValue());
    }

    private DateTime validateLastImportDate(final DateTime startDate) {
        final DateTime now = DateTime.now().withZone(DateTimeZone.UTC).minusDays(1);
        DateTime dateTime = startDate.plusDays(1);
        while (!postponeActionYDao.check(dateTime, PostponeOperationType.POST_WELCOME_EMAIL) &&
                dateTime.isBefore(now)) {
            dateTime = dateTime.plusDays(1);
        }
        if (dateTime.isBefore(now)) {
            return dateTime;
        }
        return null;
    }

    private boolean isShortMessage(WebmasterHostId hostId) {
        final Map<String, String> hostExperiments = abtService.getHostExperiments(hostId);
        final String s = hostExperiments.get(Experiment.POST_WELCOME_EMAIL.getName());
        return Strings.isNullOrEmpty(s) || SHORT.equals(s);
    }

    private boolean isEcomerseSite(WebmasterHostId hostId) {
        return false;
    }


    @Override
    public PeriodicTaskType getType() {
        return PeriodicTaskType.POST_WELCOME_EMAIL_NOTIFICATION;
    }

    @Override
    public TaskSchedule getSchedule() {
        return TaskSchedule.startByCron("0 17 * * * *");
    }

    public class TaskState implements PeriodicTaskState {
        @Getter
        long totalProcessed;
        @Getter
        long sendCount;
        @Getter
        Map<MESSAGE_TYPE, Integer> map;
        @Getter
        long european;
        @Getter
        String date;
    }

    public enum MESSAGE_TYPE {
        SHORT_CONTENT,
        SHORT_ECOMMERSE,
        LONG_CONTENT,
        LONG_ECOMMERSE
    }
}
