/*
 * 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.GET;
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.domain.model.tenant.TenantInstallationData;
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.certificate.CertificateRepository;
import com.scytl.products.ov.cr.services.domain.model.service.CertificateService;

/**
 * Endpoint for upload the information during the installation of the tenant in the system
 */
@Path(CrTenantDataResource.RESOURCE_PATH)
@Stateless(name = "cr-tenantDataResource")
public class CrTenantDataResource {
	
	public static final String RESOURCE_PATH = "tenantdata";

	public static final String SAVE_TENANT_DATA = "secured/tenant/{tenantId}";
	
	public static final String GET_TENANT_CA_CERTIFICATE = "/tenant/{tenantId}";

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

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

    @Inject
    private CertificateRepository certificateRepository;

    @Inject
    private CertificateService certificateService;

    @Inject
    private TransactionInfoProvider transactionInfoProvider;

    @Inject
    private HttpRequestService httpRequestService;

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

    /**
     * Stores
     *
     * @param tenantId
     * @param data
     * @return
     * @throws CryptographicOperationException
     * @throws ResourceNotFoundException
     * @throws DuplicateEntryException
     */
    @Path("secured/tenant/{tenantId}")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response saveTenantData(@HeaderParam(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackingId,
                                   @PathParam(QUERY_PARAMETER_TENANT_ID) final String tenantId,
                                   @NotNull final Reader data,
                                   @Context HttpServletRequest request)
        throws CryptographicOperationException, ResourceNotFoundException, DuplicateEntryException {

        trackIdInstance.setTrackId(trackingId);

        Response response;

        LOG.info("CR - received install tenant request");

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

        try {
            TenantInstallationData tenantInstallationData = ObjectMappers.fromJson(data, TenantInstallationData.class);
            CertificateEntity certificateEntity = new CertificateEntity();
            certificateEntity.setCertificateContent(tenantInstallationData.getEncodedData());
            certificateEntity.setTenantId(tenantId);
            X509CertificateValidationResult validationResult =
                certificateService.saveCertificateInDB(certificateEntity);
            if (!validationResult.isValidated()) {

                LOG.error("CR - validation failed. Setting response to failed");

                response = Response.status(Response.Status.PRECONDITION_FAILED)
                    .entity(validationResult.getFailedValidationTypes()).build();
            } else {
                LOG.info("CR - validation passed");

                response = Response.ok().build();
            }

        } catch (IOException | GeneralCryptoLibException e) {
            LOG.info("Error trying to save tenant data.", e);
            response = Response.status(Response.Status.BAD_REQUEST).build();
        }
        return response;

    }

    /**
     * Searches the tenant certificate
     *
     * @return an object with the certificate data
     * @throws DuplicateEntryException
     * @throws ResourceNotFoundException
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/tenant/{tenantId}")
    public Response getTenantCACertificate(@PathParam(QUERY_PARAMETER_TENANT_ID) final String tenantId)
        throws DuplicateEntryException, ResourceNotFoundException {

        CertificateEntity certificateEntity = certificateRepository.getTenantCertificate(tenantId);
        return Response.ok(certificateEntity).build();
    }

}
