package com.shukria.softpos.terminal;

import android.content.Context;

import com.mypinpad.tsdk.api.Terminal;
import com.mypinpad.tsdk.api.TerminalSdk;
import com.mypinpad.tsdk.api.models.PinPadConfiguration;
import com.mypinpad.tsdk.api.models.authorization.ClientCredentialsGrant;
import com.shukria.softpos.BuildConfig;
import com.shukria.softpos.config.CurrencyCustomFormattingConfig;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class TerminalProvider {
    private final Context applicationContext;

    private CompletableFuture<Terminal> terminalFuture;

    public TerminalProvider(Context applicationContext) {
        this.applicationContext = applicationContext;
    }

    public Terminal getTerminal() throws ExecutionException, InterruptedException {
        return terminalFuture.get();
    }

    /**
     * Kicks off the terminal creation.
     * <p>
     * Per the [TerminalSdk.createTerminal], this is a potentially expensive
     * background operation.
     * Because of this, it should only be called when a terminal will be or may be
     * needed, and not
     * called unconditionally from e.g. [android.app.Application.onCreate]
     *
     * @param authorizationGrant  authorization grant used for identity service
     * @param pinPadConfiguration UI configuration for PIN pad screen
     */
    public void setup(
            ClientCredentialsGrant authorizationGrant,
            PinPadConfiguration pinPadConfiguration) {
        synchronized (this) {
            if (terminalFuture != null) {
                return;
            }

            terminalFuture = new CompletableFuture<>();
        }

        TerminalSdk.createTerminal(
                applicationContext,
                new TerminalSdk.Configuration(
                        pinPadConfiguration,
                        CurrencyCustomFormattingConfig.getCurrencyCustomFormattingConfig()),
                BuildConfig.ENDPOINT,
                authorizationGrant,
                (terminal, terminalCreationFailure) -> {
                    if (terminalFuture == null) {
                        return null;
                    }

                    if (terminal != null) {
                        terminalFuture.complete(terminal);
                        return null;
                    }

                    if (terminalCreationFailure != null) {
                        terminalFuture.completeExceptionally(
                                new RuntimeException(
                                        String.format("Terminal creation failed: %s",
                                                terminalCreationFailure.getCause())));
                        return null;
                    }

                    terminalFuture.completeExceptionally(
                            new IllegalArgumentException(
                                    "Invalid response to terminal creation"));
                    return null;
                });
    }

    /**
     * Dispose current terminal
     */
    public void disposeTerminal() {
        Terminal terminal = null;
        try {
            terminal = getTerminal();
        } catch (Exception e) {
            // Error when getTerminal() can be ignored as terminalFuture will be set to null
        }

        if (terminal != null) {
            terminal.dispose();
        }

        synchronized (this) {
            if (terminalFuture != null) {
                terminalFuture.cancel(false);
                terminalFuture = null;
            }
        }
    }
}
