'use strict';

var index = require('./index-p7cvUYAE.js');
var index_esm = require('./index.esm-BNETBIV_.js');
var utils = require('./utils-CYONRFR6.js');
require('./config-state-BIgGhhe9.js');
var Plaid = require('./Plaid-CPESyiiV.js');
require('./Pagination-Dediz133.js');
require('./Business-oBifyXkW.js');
var button = require('./button-CR9Rl1-o.js');
var styledHost = require('./styled-host-Ch0-dxF-.js');
require('./event-types-YOY5TKUN.js');
var payment_service = require('./payment.service-8Q-EEtXL.js');
var getPaymentDetails = require('./get-payment-details-_rinKLxh.js');
var Analytics = require('./Analytics-C6KBHEIP.js');
var checkPkgVersion = require('./check-pkg-version-B9EoYyZR.js');
var utils$1 = require('./utils-BsnepLy6.js');
var Api = require('./Api-D9vOcUw4.js');
var skeleton = require('./skeleton-DvRCiQlA.js');
require('./_commonjsHelpers-BJu3ubxk.js');
require('./dinero-BwNN_k7x.js');
require('./index-W-zoNiyM.js');
require('./parts-BXshb_S-.js');
require('./package-YyJzVqrh.js');

const amountValidation = (maxAmount) => {
    const max = +maxAmount;
    return (index_esm.create$6()
        .required('Amount is required')
        .test('max-amount', `Refund amount cannot be more than payment amount: ${utils.formatCurrency(max)}`, function (value) {
        return +value <= +max;
    })
        .test('min-amount', 'Refund amount must be greater than 0', function (value) {
        return +value > 0;
    }));
};
const RefundPaymentSchema = (maxRefundAmount) => {
    if (!maxRefundAmount) {
        return;
    }
    const schema = index_esm.create$3({
        amount: amountValidation(maxRefundAmount),
        description: index_esm.create$6().optional(),
        reason: index_esm.create$6().optional()
            .oneOf([
            Plaid.RefundReasons.customerRequest,
            Plaid.RefundReasons.duplicate,
            Plaid.RefundReasons.fraudulent,
        ], 'Select a reason')
    });
    return schema;
};

const refundReasonOptions = [
    {
        label: 'Select a reason',
        value: '',
    },
    {
        label: 'Customer requested a refund',
        value: 'customer_request',
    },
    {
        label: 'Customer was double-charged',
        value: 'duplicate',
    },
    {
        label: 'Payment was reported as fraud',
        value: 'fraudulent',
    }
];

const makePostRefund = ({ authToken, accountId, paymentId, service }) => async ({ refundBody, onSuccess, onError, final }) => {
    var _a;
    try {
        const response = await service.postRefund(paymentId, accountId, authToken, refundBody);
        if (!response.error) {
            onSuccess(response);
        }
        else {
            const responseError = utils$1.getErrorMessage(response.error);
            const code = utils$1.getErrorCode((_a = response.error) === null || _a === void 0 ? void 0 : _a.code);
            return onError({
                error: responseError,
                code,
                severity: Plaid.ComponentErrorSeverity.ERROR,
            });
        }
    }
    catch (error) {
        const code = utils$1.getErrorCode(error === null || error === void 0 ? void 0 : error.code);
        return onError({
            error: error.message || error,
            code,
            severity: Plaid.ComponentErrorSeverity.ERROR,
        });
    }
    finally {
        final();
    }
};

const api$1 = Api.Api();
class RefundService {
    async postRefund(paymentId, accountId, authToken, refundBody) {
        const endpoint = `payments/${paymentId}/refunds`;
        const headers = { 'Sub-Account': accountId };
        const body = refundBody;
        return api$1.post({ endpoint, headers, body, authToken });
    }
}

const makePostVoid = ({ authToken, accountId, paymentId, service }) => async ({ onSuccess, onError, final }) => {
    var _a;
    try {
        const response = await service.postVoid(paymentId, accountId, authToken);
        if (!response.error) {
            onSuccess(response);
        }
        else {
            const responseError = utils$1.getErrorMessage(response.error);
            const code = utils$1.getErrorCode((_a = response.error) === null || _a === void 0 ? void 0 : _a.code);
            return onError({
                error: responseError,
                code,
                severity: Plaid.ComponentErrorSeverity.ERROR,
            });
        }
    }
    catch (error) {
        const code = utils$1.getErrorCode(error === null || error === void 0 ? void 0 : error.code);
        return onError({
            error: error.message || error,
            code,
            severity: Plaid.ComponentErrorSeverity.ERROR,
        });
    }
    finally {
        final();
    }
};

const api = Api.Api();
class VoidService {
    async postVoid(paymentId, accountId, authToken) {
        const endpoint = `payments/${paymentId}/void`;
        const headers = { 'Sub-Account': accountId };
        return api.post({ endpoint, headers, authToken });
    }
}

const FormBlock = () => (index.h("div", { class: "row gap-3" }, index.h("div", { class: "col-12" }, index.h(skeleton.Skeleton, { width: "100%", height: "40px" }))));
const RefundLoading = () => {
    return (index.h(styledHost.StyledHost, null, index.h("div", { class: "row gap-5" }, index.h(FormBlock, null), index.h(FormBlock, null), index.h(FormBlock, null))));
};

const JustifiRefundPayment = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.errorEvent = index.createEvent(this, "error-event", 7);
        this.submitEvent = index.createEvent(this, "submit-event", 7);
        this.refundPayload = {};
        this.displayAmount = '';
        this.errors = {};
        this.paymentLoading = true;
        this.refundLoading = false;
        this.hideSubmitButton = false;
        this.inputHandler = (name, value) => {
            this.formController.setValues(Object.assign(Object.assign({}, this.formController.values.getValue()), { [name]: value }));
        };
    }
    componentWillLoad() {
        checkPkgVersion.checkPkgVersion();
        this.analytics = new Analytics.JustifiAnalytics(this);
        this.initializeApi();
        this.formController = new index_esm.FormController(RefundPaymentSchema());
    }
    handleError(code, errorMessage, severity) {
        this.errorEvent.emit({ errorCode: code, message: errorMessage, severity });
    }
    checkAmount(amount) {
        return amount > 0;
    }
    handleInvalidAmount() {
        this.submitDisabled = true;
        const errorMessage = 'Refund amount must be greater than 0';
        this.handleError(Plaid.ComponentErrorCodes.INVALID_REFUND_AMOUNT, errorMessage, Plaid.ComponentErrorSeverity.ERROR);
    }
    isPaymentCreatedWithin25Minutes() {
        var _a;
        if (!this.payment || !((_a = this.payment) === null || _a === void 0 ? void 0 : _a.created_at)) {
            return false;
        }
        const paymentCreatedAt = new Date(this.payment.created_at);
        const now = new Date();
        const diffInMinutes = (now.getTime() - paymentCreatedAt.getTime()) / (1000 * 60);
        return diffInMinutes <= 25;
    }
    initializeFormController() {
        const amount = this.refundPayload.amount;
        const amountRefundable = amount ? amount.toString() : '0';
        this.formController = new index_esm.FormController(RefundPaymentSchema(amountRefundable));
        this.formController.setInitialValues({
            amount: amountRefundable
        });
        this.formController.values.subscribe(values => {
            this.refundPayload = Object.assign({}, values);
        });
        this.formController.errors.subscribe(errors => {
            this.errors = Object.assign({}, errors);
        });
    }
    initializeApi() {
        if (this.paymentId && this.authToken) {
            const getPayment = getPaymentDetails.makeGetPaymentDetails({
                id: this.paymentId,
                authToken: this.authToken,
                service: new payment_service.PaymentService()
            });
            getPayment({
                onSuccess: ({ payment }) => {
                    this.payment = payment;
                    this.refundPayload = new Plaid.RefundPayload({ amount: payment.amount_refundable });
                },
                onError: ({ error, code, severity }) => {
                    this.handleError(code, error, severity);
                },
                final: () => {
                    const amount = this.refundPayload.amount;
                    const validAmount = this.checkAmount(amount);
                    !validAmount ? this.handleInvalidAmount() : this.initializeFormController();
                    this.paymentLoading = false;
                }
            });
        }
        else {
            const errorMessage = 'Payment ID and Auth Token are required';
            this.handleError(Plaid.ComponentErrorCodes.MISSING_PROPS, errorMessage, Plaid.ComponentErrorSeverity.ERROR);
        }
    }
    async refundPayment(event) {
        event && event.preventDefault();
        const valid = await this.formController.validate();
        if (!valid)
            return;
        const values = this.formController.values.getValue();
        this.refundLoading = true;
        // Check if payment was created within 25 minutes and try to void first
        if (this.isPaymentCreatedWithin25Minutes()) {
            return this.tryVoidPayment();
        }
        // Otherwise, proceed with refund
        return this.processRefund(values);
    }
    async tryVoidPayment() {
        const postVoid = makePostVoid({
            authToken: this.authToken,
            accountId: this.accountId,
            paymentId: this.paymentId,
            service: new VoidService()
        });
        return new Promise((resolve) => {
            let voidResponse;
            let voidAttempted = false;
            const values = this.formController.values.getValue();
            postVoid({
                onSuccess: (response) => {
                    voidResponse = response;
                    voidAttempted = true;
                },
                onError: ({ error, code, severity }) => {
                    // If void fails, fall back to refund
                    voidAttempted = true;
                    this.handleError(error, code, severity);
                    this.processRefund(values)
                        .then(resolve);
                },
                final: () => {
                    if (voidResponse && !voidResponse.error && voidAttempted) {
                        this.submitEvent.emit({ response: voidResponse });
                        this.submitDisabled = true;
                        this.refundLoading = false;
                        resolve(voidResponse.data);
                    }
                },
            });
        });
    }
    async processRefund(values) {
        const postRefund = makePostRefund({
            authToken: this.authToken,
            accountId: this.accountId,
            paymentId: this.paymentId,
            service: new RefundService()
        });
        return new Promise((resolve) => {
            let refundResponse;
            postRefund({
                refundBody: values,
                onSuccess: (response) => { refundResponse = response; },
                onError: ({ error, code, severity }) => {
                    refundResponse = error;
                    this.handleError(error, code, severity);
                },
                final: () => {
                    this.submitEvent.emit({ response: refundResponse });
                    this.submitDisabled = true;
                    this.refundLoading = false;
                    resolve(refundResponse.data);
                },
            });
        });
    }
    render() {
        if (this.paymentLoading) {
            return index.h(RefundLoading, null);
        }
        const defaultValues = this.formController.getInitialValues();
        const currentRefundAmount = this.refundPayload.amount;
        return (index.h(styledHost.StyledHost, null, index.h("form", null, index.h("fieldset", null, index.h("div", { class: "row gy-3" }, index.h("div", { class: "col-12" }, index.h("form-control-monetary", { name: "amount", label: "Refund Amount", defaultValue: defaultValues.amount, inputHandler: this.inputHandler, errorText: this.errors.amount })), index.h("div", { class: "col-12" }, index.h("form-control-select", { name: "reason", label: "Reason for refund (optional)", defaultValue: defaultValues.reason, inputHandler: this.inputHandler, options: refundReasonOptions, errorText: this.errors.reason })), index.h("div", { class: "col-12" }, index.h("form-control-textarea", { name: "description", label: "Note (optional)", defaultValue: defaultValues.description, inputHandler: this.inputHandler, maxLength: 250, errorText: this.errors.description })), index.h("div", { class: "form-group d-flex flex-row-reverse" }, index.h(button.Button, { variant: "primary", type: "submit", onClick: this.refundPayment.bind(this), isLoading: this.paymentLoading || this.refundLoading, hidden: this.hideSubmitButton, disabled: this.submitDisabled }, `Refund ${utils.formatCurrency(+currentRefundAmount)}`)))))));
    }
};

exports.justifi_refund_payment = JustifiRefundPayment;
