package com.braintree.customersupportbackoffice.widgets.transaction.submitforsettlement;

import com.braintree.model.BrainTreeTransactionDetailModel;
import com.braintree.transaction.service.BrainTreePaymentTransactionService;
import com.hybris.cockpitng.engine.WidgetInstanceManager;
import de.hybris.bootstrap.annotations.UnitTest;
import org.apache.commons.lang.StringUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;

import java.math.BigDecimal;

import static com.braintree.customersupportbackoffice.constants.BraintreecustomersupportbackofficeConstants.TransactionManagementActions.WIDGET_MESSAGE_TRANSACTION_SFS_REFRESH;
import static com.braintree.customersupportbackoffice.constants.BraintreecustomersupportbackofficeConstants.TransactionManagementActions.WIDGET_TRANSACTION_SFS_TITLE;
import static org.apache.commons.lang3.StringUtils.SPACE;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class BrainTreeSubmitForSettlementTransactionControllerTest {
    private static final String TEST_TRANSACTION_ID = "TEST_TRANSACTION_ID";
    private static final String TEST_LABEL = "TEST_TITLE";
    private static final String SUBMIT_FOR_SETTLEMENT_TRANSACTION_TITLE = "braintreecustomersupportbackoffice.submitforsettlementtransaction.confirm.title";
    private static final String TEST_TRANSACTION_AMOUNT = "1 2";
    private static final String TEST_TRANSACTION_EXPECTED_AMOUNT = "1";
    private static final String TEST_AMOUNT_LABEL_ERROR = "bt.customersupport.transaction.amount.error.empty";
    private static final String TEST_AMOUNT_LABEL_ERROR_ZERO = "bt.customersupport.transaction.amount.error.zero";
    private static final String TEST_AMOUNT_LABEL_ERROR_WRONG_FORMAT = "bt.customersupport.transaction.amount.error.number.format";
    private static final String WIDGET_MESSAGE_TRANSACTION_SFS_REFRESH_LABEL = "WIDGET_MESSAGE_TRANSACTION_SFS_REFRESH_LABEL";
    private static final String TEST_AMOUNT_ERROR_WRONG_FORMAT = "TEST_AMOUNT_ERROR_WRONG_FORMAT";
    private static final String WIDGET_TRANSACTION_SFS_TITLE_LABLE = "WIDGET_TRANSACTION_SFS_TITLE_LABLE";
    private static final String TEST_AMOUNT_ERROR = "TEST_AMOUNT_ERROR";
    private static final String TEST_AMOUNT_ERROR_ZERO = "TEST_AMOUNT_ERROR_ZERO";
    private static final String WRONG_FORMAT_STRING = "WRONG_FORMAT_STRING";
    private static final String ZERO_AMOUNT = "0";
    private static final String OUT_CONFIRM = "confirm";
    private static final String SUBMITTED_FOR_SETTLEMENT = "submitted_for_settlement";
    @Mock
    private WidgetInstanceManager widgetInstanceManager;
    @Mock
    private BrainTreePaymentTransactionService brainTreePaymentTransactionService;
    @Mock
    private BrainTreeTransactionDetailModel transaction;
    @Mock
    protected Textbox amount;
    @Mock
    protected Textbox transactionId;
    @Spy
    @InjectMocks
    private BrainTreeSubmitForSettlementTransactionController unit;

    @Test
    public void shouldInitCloneForm() {
        when(transaction.getId()).thenReturn(TEST_TRANSACTION_ID);
        when(transaction.getAmount()).thenReturn(TEST_TRANSACTION_AMOUNT);
        when(widgetInstanceManager.getLabel(SUBMIT_FOR_SETTLEMENT_TRANSACTION_TITLE)).thenReturn(TEST_LABEL);
        unit.initSubmitForSettlementForm(transaction);
        verify(widgetInstanceManager).setTitle(TEST_LABEL + SPACE + TEST_TRANSACTION_ID);
    }

    @Test
    public void shouldConfirmSubmitForSettlementWhenAmountIsEmpty() {
        when(amount.getValue()).thenReturn(StringUtils.EMPTY);
        testBlankAmount();
    }

    @Test
    public void shouldConfirmSubmitForSettlementWhenAmountIsNull() {
        when(amount.getValue()).thenReturn(null);
        testBlankAmount();
    }

    @Test
    public void shouldConfirmSubmitForSettlementWhenAmountIsWhiteSpace() {
        when(amount.getValue()).thenReturn(SPACE);
        testBlankAmount();
    }

    @Test
    public void shouldConfirmSubmitForSettlementWhenThrownNumberFormatException() {
        when(amount.getValue()).thenReturn(WRONG_FORMAT_STRING);
        when(widgetInstanceManager.getLabel(TEST_AMOUNT_LABEL_ERROR_WRONG_FORMAT)).thenReturn(TEST_AMOUNT_ERROR_WRONG_FORMAT);
        WrongValueException throwable = Assert.assertThrows(WrongValueException.class, () -> unit.confirmSubmitForSettlement());
        Assert.assertEquals(TEST_AMOUNT_ERROR_WRONG_FORMAT, throwable.getMessage());
    }

    @Test
    public void shouldConfirmSubmitForSettlement() {
        when(amount.getValue()).thenReturn(TEST_TRANSACTION_EXPECTED_AMOUNT);
        when(widgetInstanceManager.getLabel(WIDGET_MESSAGE_TRANSACTION_SFS_REFRESH)).thenReturn(WIDGET_MESSAGE_TRANSACTION_SFS_REFRESH_LABEL);
        when(widgetInstanceManager.getLabel(WIDGET_TRANSACTION_SFS_TITLE)).thenReturn(WIDGET_TRANSACTION_SFS_TITLE_LABLE);
        doNothing().when(unit).showMsg(any(), any(), anyInt(), any());
        unit.confirmSubmitForSettlement();
        verify(brainTreePaymentTransactionService).continueSubmitOrder(transaction, new BigDecimal(TEST_TRANSACTION_EXPECTED_AMOUNT));
        verify(unit).showMsg(WIDGET_MESSAGE_TRANSACTION_SFS_REFRESH_LABEL, WIDGET_TRANSACTION_SFS_TITLE_LABLE, Messagebox.OK, Messagebox.INFORMATION);
        verify(widgetInstanceManager).sendOutput(OUT_CONFIRM, SUBMITTED_FOR_SETTLEMENT);
    }

    @Test
    public void shouldConfirmCloneWhenAmountIsZero() {
        when(amount.getValue()).thenReturn(ZERO_AMOUNT);
        when(widgetInstanceManager.getLabel(TEST_AMOUNT_LABEL_ERROR_ZERO)).thenReturn(TEST_AMOUNT_ERROR_ZERO);
        WrongValueException throwable = Assert.assertThrows(WrongValueException.class, () -> unit.confirmSubmitForSettlement());
        Assert.assertEquals(TEST_AMOUNT_ERROR_ZERO, throwable.getMessage());
    }

    private void testBlankAmount() {
        when(widgetInstanceManager.getLabel(TEST_AMOUNT_LABEL_ERROR)).thenReturn(TEST_AMOUNT_ERROR);
        WrongValueException throwable = Assert.assertThrows(WrongValueException.class, () -> unit.confirmSubmitForSettlement());
        Assert.assertEquals(TEST_AMOUNT_ERROR, throwable.getMessage());
    }

}
