package ru.yandex.webmaster3.coordinator.http;

import com.google.protobuf.Message;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import ru.yandex.webmaster3.coordinator.ReceiverStatusService;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.ActionResponse;
import ru.yandex.webmaster3.core.http.ActionStatus;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author aherman
 */
public abstract class AbstractReceiveAction<Req extends AbstractReceiveRequest, Resp extends ActionResponse, Mess extends Message>
        extends BaseCoordinatorAction<Req, Resp>
{
    private static final Logger log = LoggerFactory.getLogger(AbstractReceiveAction.class);

    private ReceiverStatusService receiverStatusService;

    @Override
    public final Resp process(Req request) throws WebmasterException {
        ReceiverStatusService.ReceiverType receiveType = request.getReceiveType();
        receiverStatusService.messageReceived(receiveType);
        if (!receiverStatusService.isReceiverEnabled(receiveType)) {
            // Skip message
            receiverStatusService.messageSkipped(receiveType);
            return null;
        }
        Resp response = doProcess(request);
        if (response.getRequestStatus() == ActionStatus.SUCCESS) {
            receiverStatusService.messageProcessed(receiveType);
        }
        return response;
    }

    protected Mess getMessage(AbstractReceiveRequest request) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(16536);
        InputStream contentInputStream = request.getContentInputStream();

        int dataSize;
        try {
            dataSize = IOUtils.copy(contentInputStream, baos);
        } catch (IOException e) {
            throw new WebmasterException("Unable to read data",
                    new WebmasterErrorResponse.InternalUnknownErrorResponse(this.getClass(), "Unable to read data"), e);
        } finally {
            IOUtils.closeQuietly(contentInputStream);
        }
        log.info("Message size: {} bytes", dataSize);
        byte[] bytes = baos.toByteArray();
        Mess message = null;
        try {
            message = decodeProtobuf(new ByteArrayInputStream(bytes));
        } catch (IOException e) {
            throw new WebmasterException("Unable to parse request protobuf",
                    new WebmasterErrorResponse.InternalUnknownErrorResponse(this.getClass(), "Unable to parse request protobuf"), e);
        }
        return message;
    }

    protected abstract Mess decodeProtobuf(InputStream is) throws IOException;

    protected abstract Resp doProcess(Req request);

    @Required
    public void setReceiverStatusService(ReceiverStatusService receiverStatusService) {
        this.receiverStatusService = receiverStatusService;
    }
}
