package com.ease.gsms.server.model;

import com.ease.gsms.server.services.dispatch.DispatchStatusHolder;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.function.Function.identity;

public class Dispatch {

    Long id;

    UUID uuid;

    String fromICCID;

    String submitter;

    Date submissionDate;

    Date modificationDate;

    Boolean sendToInternationalNumbers;

    Boolean sendToNationalLandlines;

    Boolean sendToNationalMobiles;

    Boolean resendIdenticalSuccessfullyDeliveredMessages;

    Boolean resendIdenticalSuccessfullySentMessages;

    Boolean resendIdenticalUnsuccessfullySentMessages;

    Boolean resendUnsentMessages;

    Boolean askForDeliveryReport;

    Integer pauseBetweenMessagesSeconds;

    volatile DispatchStatus status;

    List<Message> messages;

    int messageCount;

    Map<Long, Message> messagesById = null;

    transient DispatchStatusHolder dispatchStatusHolder;

    public Dispatch(
            Long id,
            UUID uuid,
            String fromICCID,
            String submitter,
            Date submissionDate,
            Date modificationDate,
            Boolean sendToInternationalNumbers,
            Boolean sendToNationalLandlines,
            Boolean sendToNationalMobiles,
            Boolean resendIdenticalSuccessfullyDeliveredMessages,
            Boolean resendIdenticalSuccessfullySentMessages,
            Boolean resendIdenticalUnsuccessfullySentMessages,
            Boolean resendUnsentMessages,
            Boolean askForDeliveryReport,
            Integer pauseBetweenMessagesSeconds,
            DispatchStatus status,
            Message[] messages
    ) {
        this.id = id;
        this.uuid = uuid;
        this.fromICCID = fromICCID;
        this.submitter = submitter;
        this.submissionDate = submissionDate;
        this.modificationDate = modificationDate;
        this.sendToInternationalNumbers = sendToInternationalNumbers;
        this.sendToNationalLandlines = sendToNationalLandlines;
        this.sendToNationalMobiles = sendToNationalMobiles;
        this.resendIdenticalSuccessfullyDeliveredMessages = resendIdenticalSuccessfullyDeliveredMessages;
        this.resendIdenticalSuccessfullySentMessages = resendIdenticalSuccessfullySentMessages;
        this.resendIdenticalUnsuccessfullySentMessages = resendIdenticalUnsuccessfullySentMessages;
        this.resendUnsentMessages = resendUnsentMessages;
        this.askForDeliveryReport = askForDeliveryReport;
        this.pauseBetweenMessagesSeconds = pauseBetweenMessagesSeconds;
        this.status = status;
        setMessages(messages);
    }

    public Dispatch(
            Long id,
            UUID uuid,
            String fromICCID,
            String submitter,
            Date submissionDate,
            Date modificationDate,
            Boolean sendToInternationalNumbers,
            Boolean sendToNationalLandlines,
            Boolean sendToNationalMobiles,
            Boolean resendIdenticalSuccessfullyDeliveredMessages,
            Boolean resendIdenticalSuccessfullySentMessages,
            Boolean resendIdenticalUnsuccessfullySentMessages,
            Boolean resendUnsentMessages,
            Boolean askForDeliveryReport,
            Integer pauseBetweenMessagesSeconds,
            DispatchStatus status,
            int messageCount
    ) {
        this.id = id;
        this.uuid = uuid;
        this.fromICCID = fromICCID;
        this.submitter = submitter;
        this.submissionDate = submissionDate;
        this.modificationDate = modificationDate;
        this.sendToInternationalNumbers = sendToInternationalNumbers;
        this.sendToNationalLandlines = sendToNationalLandlines;
        this.sendToNationalMobiles = sendToNationalMobiles;
        this.resendIdenticalSuccessfullyDeliveredMessages = resendIdenticalSuccessfullyDeliveredMessages;
        this.resendIdenticalSuccessfullySentMessages = resendIdenticalSuccessfullySentMessages;
        this.resendIdenticalUnsuccessfullySentMessages = resendIdenticalUnsuccessfullySentMessages;
        this.resendUnsentMessages = resendUnsentMessages;
        this.askForDeliveryReport = askForDeliveryReport;
        this.pauseBetweenMessagesSeconds = pauseBetweenMessagesSeconds;
        this.status = status;
        this.messageCount = messageCount;
    }

    public Dispatch(
            String fromICCID,
            String submitter,
            Boolean sendToInternationalNumbers,
            Boolean sendToNationalLandlines,
            Boolean sendToNationalMobiles,
            Boolean resendIdenticalSuccessfullyDeliveredMessages,
            Boolean resendIdenticalSuccessfullySentMessages,
            Boolean resendIdenticalUnsuccessfullySentMessages,
            Boolean resendUnsentMessages,
            Boolean askForDeliveryReport,
            Integer pauseBetweenMessagesSeconds,
            Message[] messages
    ) {
        this(null, null, fromICCID, submitter, new Date(), new Date(), sendToInternationalNumbers, sendToNationalLandlines, sendToNationalMobiles, resendIdenticalSuccessfullyDeliveredMessages, resendIdenticalSuccessfullySentMessages, resendIdenticalUnsuccessfullySentMessages, resendUnsentMessages, askForDeliveryReport, pauseBetweenMessagesSeconds, DispatchStatus.REQUESTED, messages);
    }

    public Long getId() {
        return id;
    }

    public UUID getUUID() {
        return uuid;
    }

    public String getFromICCID() {
        return fromICCID;
    }

    public String getSubmitter() {
        return submitter;
    }

    public Date getSubmissionDate() {
        return submissionDate;
    }

    public Date getModificationDate() {
        return modificationDate;
    }

    public Boolean getSendToInternationalNumbers() {
        return sendToInternationalNumbers;
    }

    public Boolean getSendToNationalLandlines() {
        return sendToNationalLandlines;
    }

    public Boolean getSendToNationalMobiles() {
        return sendToNationalMobiles;
    }

    public Boolean getResendIdenticalSuccessfullyDeliveredMessages() {
        return resendIdenticalSuccessfullyDeliveredMessages;
    }

    public Boolean getResendIdenticalSuccessfullySentMessages() {
        return resendIdenticalSuccessfullySentMessages;
    }

    public Boolean getResendIdenticalUnsuccessfullySentMessages() {
        return resendIdenticalUnsuccessfullySentMessages;
    }

    public Boolean getResendUnsentMessages() {
        return resendUnsentMessages;
    }

    public List<Message> getMessages() {
        return messages;
    }

    public Boolean getAskForDeliveryReport() {
        return askForDeliveryReport;
    }

    public Integer getPauseBetweenMessagesSeconds() {
        return pauseBetweenMessagesSeconds;
    }

    public DispatchStatus getStatus() {
        return status;
    }

    public void setStatus(DispatchStatus status) {
        this.status = status;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setUUID(UUID uuid) {
        this.uuid = uuid;
    }

    public int getUnsentMessageCount() {

        return (int) unsent().count();

    }

    public static boolean isUnsent(Message m) {
        return m.isUnsent();
    }

    public Stream<Message> unsent() {
        return messages
                .stream()
                .filter(Dispatch::isUnsent);
    }

    public void setMessages(Message[] messages) {
        setMessages(messages != null ? Arrays.asList(messages) : new LinkedList<>());
    }

    public void setMessages(List<Message> messages) {
        this.messages = Collections.synchronizedList(messages);
        messageCount = this.messages.size();
    }

    public int getMessageCount() {
        return messageCount;
    }

    public synchronized Map<Long, Message> getMessagesById() {
        if (this.messagesById != null) {
            return this.messagesById;
        } else {
            return this.messagesById = this.messages.stream().collect(Collectors.toMap(Message::getId, identity()));
        }
    }

    public DispatchStatusHolder getDispatchStatusHolder() {
        return dispatchStatusHolder;
    }

    public void setDispatchStatusHolder(DispatchStatusHolder dispatchStatusHolder) {
        this.dispatchStatusHolder = dispatchStatusHolder;
    }

}
