package meerkat.pollingstation;

import com.google.protobuf.BoolValue;
import meerkat.pollingstation.controller.callbacks.ScanCallback;
import meerkat.pollingstation.controller.callbacks.ScanDataCallback;
import meerkat.pollingstation.controller.callbacks.ScanErrorCallback;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.PollingStation;

import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import java.util.concurrent.LinkedBlockingQueue;

import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_CONNECT_PATH;
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH;
import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF;

/**
 * Implements a Web-App interface for {@link PollingStationScanner.ScannerClient}
 * This class depends on {@link meerkat.pollingstation.ReceiverScanHandler} and works in conjunction with it
 */
@Path("/")
public class ReceiverWebAPI implements PollingStationScanner.ScannerClient {

    @Context
    ServletContext servletContext;

    LinkedBlockingQueue<ScanCallback> callbacks;

    /**
     * This method is called by the Jetty engine when instantiating the servlet
     */
    @PostConstruct
    @SuppressWarnings("unchecked")
    public void init() throws Exception {
        Object context = servletContext.getAttribute(ReceiverScanHandler.CALLBACKS_ATTRIBUTE_NAME);

        try {
            callbacks = (LinkedBlockingQueue<ScanCallback>) context;
        } catch (ClassCastException e) {
            throw e;
        }

    }


    @POST
    @Path(POLLING_STATION_WEB_SCANNER_CONNECT_PATH)
    @Consumes(MEDIATYPE_PROTOBUF)
    @Produces(MEDIATYPE_PROTOBUF)
    @Override
    public BoolValue connect(PollingStation.ConnectionClientData clientData) {

        boolean sent = false;

        try {
            ScanDataCallback callback = new ScanDataCallback(scannedData);

            callbacks.add(callback);
            sent = true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return BoolValue.newBuilder()
                .setValue(sent)
                .build();

    }

    @POST
    @Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH)
    @Consumes(MEDIATYPE_PROTOBUF)
    @Produces(MEDIATYPE_PROTOBUF)
    @Override
    public BoolValue newScan(PollingStation.ScannedData scannedData, Crypto.Signature scannedDataSignature) {

        boolean sent = false;

//        for (FutureCallback<PollingStation.ScannedData> callback : callbacks){
//
//            callback.onSuccess(scannedData);
//            handled = true;
//
//        }
        try {
            ScanDataCallback callback = new ScanDataCallback(scannedData);
//        scanner.subscribe(callback);
            callbacks.add(callback);
            sent = true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return BoolValue.newBuilder()
                .setValue(sent)
                .build();

    }

    @POST
    @Path(POLLING_STATION_WEB_SCANNER_ERROR_PATH)
    @Consumes(MEDIATYPE_PROTOBUF)
    @Produces(MEDIATYPE_PROTOBUF)
    @Override
    public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg, Crypto.Signature errorMsgSignature) {

        boolean handled = false;

//        for (FutureCallback<PollingStation.ScannedData> callback : callbacks){
//
//            callback.onFailure(new IOException(errorMsg.getMsg()));
//            handled = true;
//
//        }

        ScanErrorCallback callback = new ScanErrorCallback(errorMsg);
//        scanner.subscribe(callback);
        callbacks.add(callback);

        return BoolValue.newBuilder()
                .setValue(handled)
                .build();

    }


}
