/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.cr.ui.ws.rs.operation;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.Reader;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.certificates.configuration.X509CertificateValidationResult;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;
import com.scytl.products.ov.commons.beans.exceptions.DuplicateEntryException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.ui.Constants;
import com.scytl.products.ov.commons.ui.ws.rs.ObjectMappers;
import com.scytl.products.ov.commons.util.HttpRequestService;
import com.scytl.products.ov.cr.services.domain.model.certificate.CertificateEntity;
import com.scytl.products.ov.cr.services.domain.model.service.CertificateService;

/**
 * Private Certificate Registry Resource
 */
@Path("certificates/private")
@Stateless(name = "cert-PrivateCertificatesDataResource")
public class PrivateCertificateRegistryResource {

    private static final Logger LOG = LoggerFactory.getLogger("std");

    // The name of the query parameter tenantId
    private static final String QUERY_PARAMETER_TENANT_ID = "tenantId";

    // The name of the query parameter electionEventId
    private static final String QUERY_PARAMETER_ELECTION_EVENT_ID = "electionEventId";

    @Inject
    private CertificateService certificateService;

    @Inject
    private TransactionInfoProvider transactionInfoProvider;

    @Inject
    private HttpRequestService httpRequestService;

    // The track id instance
    @Inject
    private TrackIdInstance trackIdInstance;

    @POST
    @Path("tenant/{tenantId}/electionevent/{electionEventId}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response saveCertificate(@HeaderParam(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackingId,
                                    @PathParam(QUERY_PARAMETER_TENANT_ID) String tenantId,
                                    @PathParam(QUERY_PARAMETER_ELECTION_EVENT_ID) String electionEventId,
                                    @NotNull Reader certificateReader,
                                    @Context HttpServletRequest request)
        throws DuplicateEntryException, ResourceNotFoundException, CryptographicOperationException {

        trackIdInstance.setTrackId(trackingId);
        transactionInfoProvider.generate(tenantId, httpRequestService.getIpClientAddress(request),
            httpRequestService.getIpServer(request));

        Response response;
        try {
            CertificateEntity certificateEntity = ObjectMappers.fromJson(certificateReader, CertificateEntity.class);
            certificateEntity.setElectionEventId(electionEventId);
            certificateEntity.setTenantId(tenantId);

            X509CertificateValidationResult validationResult = certificateService.saveCertificateInDB(certificateEntity);
            if (!validationResult.isValidated()) {
                response = Response.status(Response.Status.PRECONDITION_FAILED).build();
            } else {
                response = Response.ok().build();
            }

        } catch (IOException | GeneralCryptoLibException e) {
            LOG.error("Failed to save certificate.", e);
            response = Response.status(Response.Status.BAD_REQUEST).build();
        }
        return response;
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response saveCertificate(@HeaderParam(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackingId,
                                    @NotNull Reader certificateReader,
                                    @Context HttpServletRequest request) throws DuplicateEntryException,
        ResourceNotFoundException, CryptographicOperationException {

        trackIdInstance.setTrackId(trackingId);
        transactionInfoProvider.generate("", httpRequestService.getIpClientAddress(request),
            httpRequestService.getIpServer(request));

        Response response;
        try {
            CertificateEntity certificateEntity = ObjectMappers.fromJson(certificateReader, CertificateEntity.class);

            X509CertificateValidationResult validationResult = certificateService.saveCertificateInDB(certificateEntity);
            if (!validationResult.isValidated()) {
                response = Response.status(Response.Status.PRECONDITION_FAILED).build();
            } else {
                response = Response.ok().build();
            }
        } catch (IOException | GeneralCryptoLibException e) {
            LOG.error("Failed to save certificate.", e);
            response = Response.status(Response.Status.BAD_REQUEST).build();
        }
        return response;
    }
}
