package com.braintreeocc.controllers;

import de.hybris.platform.commercefacades.order.data.CCPaymentInfoData;
import de.hybris.platform.commercefacades.user.UserFacade;
import de.hybris.platform.commerceservices.request.mapping.annotation.RequestMappingOverride;
import de.hybris.platform.commercewebservicescommons.dto.order.PaymentDetailsWsDTO;
import de.hybris.platform.commercewebservicescommons.errors.exceptions.RequestParameterException;
import de.hybris.platform.core.PK;
import de.hybris.platform.webservicescommons.cache.CacheControl;
import de.hybris.platform.webservicescommons.cache.CacheControlDirective;
import de.hybris.platform.webservicescommons.swagger.ApiBaseSiteIdAndUserIdParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.annotation.Resource;

@Controller
@RequestMapping(value = "/{baseSiteId}/users/{userId}/paymentdetails")
@CacheControl(directive = CacheControlDirective.PRIVATE)
@Tag(name = "Payment Details")
public class BraintreePaymentDetailsController extends BraintreeBaseController{

    private static final Logger LOG = LoggerFactory.getLogger(BraintreePaymentDetailsController.class);

    private static final String OBJECT_NAME_PAYMENT_DETAILS = "paymentDetails";

    @Resource(name = "userFacade")
    private UserFacade userFacade;

    @Resource(name = "brainTreePaymentInfoValidator")
    private Validator brainTreePaymentInfoValidator;

    @Secured({ "ROLE_CUSTOMERGROUP", "ROLE_TRUSTED_CLIENT", "ROLE_CUSTOMERMANAGERGROUP" })
    @RequestMappingOverride
    @RequestMapping(value = "/{paymentDetailsId}", method = RequestMethod.PATCH, consumes = { MediaType.APPLICATION_JSON_VALUE,
            MediaType.APPLICATION_XML_VALUE })
    @Operation(operationId = "updatePaymentDetails", summary = "Updates existing customer's credit card payment details.", description =
            "Updates an existing customer's credit card payment details based "
                    + "on the specified paymentDetailsId. Only those attributes provided in the request will be updated.")
    @ApiBaseSiteIdAndUserIdParam
    @ResponseStatus(HttpStatus.OK)
    public void updatePaymentDetails(
            @Parameter(description = "Payment details identifier.", required = true) @PathVariable final String paymentDetailsId,
            @Parameter(description = "Payment details object", required = true) @RequestBody final PaymentDetailsWsDTO paymentDetails)
    {
        final CCPaymentInfoData paymentInfoData = getPaymentInfo(paymentDetailsId);
        final boolean isAlreadyDefaultPaymentInfo = paymentInfoData.isDefaultPaymentInfo();

        getDataMapper().map(paymentDetails, paymentInfoData,
                "accountHolderName,cardNumber,cardType,issueNumber,startMonth,expiryMonth,startYear,expiryYear,subscriptionId,defaultPaymentInfo,saved,"
                        + "billingAddress(firstName,lastName,titleCode,line1,line2,town,postalCode,region(isocode),country(isocode),defaultAddress)",
                false);
        validate(paymentInfoData, OBJECT_NAME_PAYMENT_DETAILS, brainTreePaymentInfoValidator);

        userFacade.updateCCPaymentInfo(paymentInfoData);
        if (paymentInfoData.isSaved() && !isAlreadyDefaultPaymentInfo && paymentInfoData.isDefaultPaymentInfo())
        {
            userFacade.setDefaultPaymentInfo(paymentInfoData);
        }
    }

    public CCPaymentInfoData getPaymentInfo(final String paymentDetailsId)
    {
        LOG.debug("getPaymentInfo : id = {}", sanitize(paymentDetailsId));
        try
        {
            final CCPaymentInfoData paymentInfoData = userFacade.getCCPaymentInfoForCode(paymentDetailsId);
            if (paymentInfoData == null)
            {
                throw new RequestParameterException("Payment details [" + sanitize(paymentDetailsId) + "] not found.",
                        RequestParameterException.UNKNOWN_IDENTIFIER, "paymentDetailsId");
            }
            return paymentInfoData;
        }
        catch (final PK.PKException e)
        {
            throw new RequestParameterException("Payment details [" + sanitize(paymentDetailsId) + "] not found.",
                    RequestParameterException.UNKNOWN_IDENTIFIER, "paymentDetailsId", e);
        }
    }

}
