package demo.mapi.ccv.eu.mapi_demo.handlers;

import java.text.SimpleDateFormat;
import java.util.Date;

import demo.mapi.ccv.eu.mapi_demo.DelegationFactory;
import demo.mapi.ccv.eu.mapi_demo.Flow;
import demo.mapi.ccv.eu.mapi_demo.MapiDemoState;
import eu.ccvlab.mapi.api.OpiNLService;
import eu.ccvlab.mapi.api.PaymentService;
import eu.ccvlab.mapi.api.TerminalService;
import eu.ccvlab.mapi.core.RequestType;
import eu.ccvlab.mapi.core.api.OpiNLApi;
import eu.ccvlab.mapi.core.api.PaymentApi;
import eu.ccvlab.mapi.core.api.TerminalApi;
import eu.ccvlab.mapi.core.api.request.CardDetectionRequest;
import eu.ccvlab.mapi.core.api.request.OnlineAgentRequest;
import eu.ccvlab.mapi.core.api.response.delegate.PaymentDelegate;
import eu.ccvlab.mapi.core.api.response.delegate.TerminalDelegate;
import eu.ccvlab.mapi.core.api.response.delegate.TokenDelegate;
import eu.ccvlab.mapi.core.payment.Money;
import eu.ccvlab.mapi.core.payment.Payment;
import eu.ccvlab.mapi.core.terminal.ExternalTerminal;

public class OpiNlFlowHandler implements PaymentHandler {
    private final DelegationFactory delegationFactory;
    private final SimpleDateFormat posTimestampFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ");
    private final MapiDemoState appState;

    public OpiNlFlowHandler(DelegationFactory delegationFactory, MapiDemoState appState) {
        this.delegationFactory = delegationFactory;
        this.appState = appState;
    }

    @Override
    public void startRefund(ExternalTerminal externalTerminal, Payment.Type type, Money money, Integer referenceNumber) {
        Payment payment = Payment
                .builder()
                .type(type)
                .amount(money)
                .posTimestamp(posTimestampFormatter.format(new Date()))
                .referenceNumber(referenceNumber)
                .myCCVShopLocationId(appState.getMyCCVShopLocationId(appState.selectedOpiProtocol()))
                .build();
        PaymentDelegate delegate = delegationFactory.createPaymentDelegate(Flow.REFUND.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.payment(externalTerminal, payment, delegate);
    }

    @Override
    public void startPayment(ExternalTerminal externalTerminal, Payment payment) {
        PaymentDelegate delegate = delegationFactory.createPaymentDelegate(Flow.PAYMENT.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.payment(externalTerminal, payment, delegate);
    }

    @Override
    public void startSaleAfterReservation(ExternalTerminal externalTerminal, Payment.Type type, Money money, String approvalCode, String token) {
        Payment payment = Payment
                .builder()
                .type(type)
                .amount(money)
                .approvalCode(approvalCode)
                .token(token)
                .posTimestamp(posTimestampFormatter.format(new Date()))
                .build();
        PaymentDelegate delegate = delegationFactory.createPaymentDelegate(Flow.SALES_AFTER_RESERVATION.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.payment(externalTerminal, payment, delegate);
    }

    @Override
    public void startCardReservation(ExternalTerminal externalTerminal, Payment.Type type, Money money) {
        Payment payment = Payment
                .builder()
                .type(type)
                .amount(money)
                .posTimestamp(posTimestampFormatter.format(new Date()))
                .build();
        PaymentDelegate delegate = delegationFactory.createPaymentDelegate(Flow.CARD_RESERVATION.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.reservation(externalTerminal, payment, delegate);
    }

    @Override
    public void startReservationAdjustment(ExternalTerminal externalTerminal, Payment.Type type, Money money, String approvalCode) {
        Payment payment = Payment
                .builder()
                .type(type)
                .amount(money)
                .approvalCode(approvalCode)
                .posTimestamp(posTimestampFormatter.format(new Date()))
                .build();
        PaymentDelegate delegate = delegationFactory.createPaymentDelegate(Flow.RESERVATION_ADJUSTMENT.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.reservation(externalTerminal, payment, delegate);
    }

    @Override
    public void startReservationAdjustmentNoCardPresent(ExternalTerminal externalTerminal, Payment.Type type, Money money, String approvalCode, String token) {
        Payment payment = Payment
                .builder()
                .type(type)
                .amount(money)
                .approvalCode(approvalCode)
                .token(token)
                .posTimestamp(posTimestampFormatter.format(new Date()))
                .build();
        PaymentDelegate delegate = delegationFactory.createPaymentDelegate(Flow.RESERVATION_ADJUSTMENT_NO_CARD_PRESENT.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.reservation(externalTerminal, payment, delegate);
    }

    @Override
    public void startVoid(ExternalTerminal externalTerminal, Payment.Type type, Money money, String approvalCode, RequestType originalRequestType, String token) {
        Payment payment = Payment
                .builder()
                .type(type)
                .amount(money)
                .token(token)
                .originalTransactionRequestType(originalRequestType)
                .approvalCode(approvalCode)
                .posTimestamp(posTimestampFormatter.format(new Date()))
                .build();

        PaymentDelegate paymentDelegate = delegationFactory.createPaymentDelegate(Flow.VOID.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.payment(externalTerminal, payment, paymentDelegate);
    }

    @Override
    public void startStatus(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.STATUS.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.status(externalTerminal, delegate);
    }

    @Override
    public void startRetrieveLastTicket(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.RETRIEVE_LAST_TICKET.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.retrieveLastTicket(externalTerminal, delegate);
    }

    @Override
    public void startRepeatLastMessage(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.REPEAT_LAST_PAYMENT.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.repeatLastMessage(externalTerminal, delegate);

    }

    @Override
    public void startAbort(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.ABORT.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.abort(externalTerminal, delegate);
    }

    @Override
    public void startAbortOnNewConnection(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.ABORT_ON_NEW_CONNECTION.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.abortOnNewConnection(externalTerminal, delegate);
    }

    @Override
    public void showTerminalMenu(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.SHOW_MENU.description());
        OpiNLApi opiNLService = new OpiNLService();
        opiNLService.displayStartMenu(externalTerminal, delegate);
    }

    @Override
    public void getTransactionOverview(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.TRANSACTION_OVERVIEW.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.transactionOverview(externalTerminal, delegate);
    }

    @Override
    public void performPeriodClosing(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.PERFORM_PERIOD_CLOSING.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.periodClosing(externalTerminal, delegate);
    }

    @Override
    public void recoverPayment(ExternalTerminal externalTerminal, String paymentRequestId) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.RECOVER_PAYMENT.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.recoverPayment(externalTerminal, paymentRequestId, delegate);
    }

    @Override
    public void cardCircuits(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.CARD_CIRCUITS.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.cardCircuits(externalTerminal, delegate);
    }

    @Override
    public void startReadUID(ExternalTerminal externalTerminal) {
        TokenDelegate delegate = delegationFactory.createTokenDelegate(Flow.READ_UID.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.readMifareUID(externalTerminal, delegate);
    }

    @Override
    public void flexo(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.FLEXO.description());
        PaymentApi paymentService = new PaymentService();
        paymentService.flexo(externalTerminal, delegate);
    }

    @Override
    public void cardDetection(ExternalTerminal externalTerminal, CardDetectionRequest cardDetectionRequest) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.CARD_DETECTION.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.cardDetection(externalTerminal, cardDetectionRequest, delegate);
    }

    @Override
    public void silentAbort(ExternalTerminal externalTerminal) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.SILENT_ABORT.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.abortOnNewConnection(true, externalTerminal, delegate);
    }

    @Override
    public void onlineAgent(ExternalTerminal externalTerminal, OnlineAgentRequest onlineAgentRequest) {
        TerminalDelegate delegate = delegationFactory.createPaymentAdministrationDelegate(Flow.ONLINE_AGENT_FLEXO.description());
        TerminalApi terminalService = new TerminalService();
        terminalService.onlineAgent(externalTerminal, onlineAgentRequest, delegate);
    }
}
