package com.shukria.softpos.ui;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.ComponentActivity;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;

import com.mypinpad.android.hapticslibrary.CardScheme;
import com.mypinpad.android.hapticslibrary.SchemeHapticsAnimationView;
import com.mypinpad.tsdk.api.Terminal;
import com.mypinpad.tsdk.api.callbacks.SessionActivationFailureCause;
import com.mypinpad.tsdk.api.callbacks.UiMessage;
import com.mypinpad.tsdk.api.models.TransactionType;
import com.shukria.softpos.ExampleApp;
import com.shukria.softpos.R;
import com.shukria.softpos.Utils;

public class SoftPosActivity extends ComponentActivity {

    private MainViewModel viewModel;

    // Overlays
    private View mainContent;
    private LinearLayout processingOverlay;
    private TextView processingMessage;
    private ProgressBar processingSpinner;
    private LinearLayout resultOverlay;
    private TextView resultIcon;
    private TextView resultMessage;
    private View retryButton;
    private View settingsButton;
    private SchemeHapticsAnimationView schemeHapticsAnimationView;

    // Payment grid buttons
    private View btnCardSale;
    private View btnQrPay;
    private View btnPayLink;
    private View btnSplitBill;
    private View btnRefund;
    private View btnVoid;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Utils.deviceNfcStatus(this) != Utils.DeviceNfcStatus.NFC_ENABLED) {
            startActivity(new Intent(this, NfcErrorActivity.class));
            finish();
            return;
        }

        setContentView(R.layout.activity_softpos);
        viewModel = new ViewModelProvider(this).get(MainViewModel.class);

        bindViews();
        setupClickListeners();
    }

    @Override
    protected void onStart() {
        super.onStart();
        viewModel.getLogger().sink = (msg) -> null; // suppress logs in softpos mode
        viewModel.getViewData().observe(this, this::updateUi);

        // Auto-initialize terminal when we enter the activity
        ViewData current = viewModel.getViewData().getValue();
        if (current instanceof ViewData.TerminalNotCreatedViewData) {
            showProcessingOverlay(getString(R.string.overlay_initializing));
            viewModel.createTerminal();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        viewModel.getLogger().sink = ExampleApp.TsdkLogger.DEFAULT_SINK;
        viewModel.getViewData().removeObservers(this);
    }

    private void bindViews() {
        mainContent = findViewById(R.id.mainContent);
        processingOverlay = findViewById(R.id.processingOverlay);
        processingMessage = findViewById(R.id.processingMessage);
        processingSpinner = findViewById(R.id.processingSpinner);
        resultOverlay = findViewById(R.id.resultOverlay);
        resultIcon = findViewById(R.id.resultIcon);
        resultMessage = findViewById(R.id.resultMessage);
        retryButton = findViewById(R.id.retryButton);
        settingsButton = findViewById(R.id.settingsButton);
        schemeHapticsAnimationView = findViewById(R.id.transactionProcessedView);

        btnCardSale = findViewById(R.id.btnCardSale);
        btnQrPay = findViewById(R.id.btnQrPay);
        btnPayLink = findViewById(R.id.btnPayLink);
        btnSplitBill = findViewById(R.id.btnSplitBill);
        btnRefund = findViewById(R.id.btnRefund);
        btnVoid = findViewById(R.id.btnVoid);

        findViewById(R.id.settingsIcon).setOnClickListener(
                v -> startActivity(new Intent(this, SettingsActivity.class)));
        settingsButton.setOnClickListener(
                v -> startActivity(new Intent(this, SettingsActivity.class)));
    }

    private void setupClickListeners() {
        btnCardSale.setOnClickListener(v -> onPaymentOptionSelected(TransactionType.PURCHASE));
        btnRefund.setOnClickListener(v -> onPaymentOptionSelected(TransactionType.REFUND));

        // Not yet implemented options
        View.OnClickListener comingSoon = v ->
                Toast.makeText(this, R.string.coming_soon, Toast.LENGTH_SHORT).show();
        btnQrPay.setOnClickListener(comingSoon);
        btnPayLink.setOnClickListener(comingSoon);
        btnSplitBill.setOnClickListener(comingSoon);
        btnVoid.setOnClickListener(comingSoon);

        retryButton.setOnClickListener(v -> {
            hideResultOverlay();
            showProcessingOverlay(getString(R.string.overlay_initializing));
            viewModel.createTerminal();
        });
    }

    private void onPaymentOptionSelected(TransactionType type) {
        ViewData current = viewModel.getViewData().getValue();
        if (current instanceof ViewData.TerminalInSessionViewData) {
            showProcessingOverlay(getString(R.string.overlay_processing));
            viewModel.startTransaction((ViewData.TerminalInSessionViewData) current, type, 0L);
        } else {
            Toast.makeText(this, getString(R.string.overlay_initializing), Toast.LENGTH_SHORT).show();
        }
    }

    private void updateUi(ViewData viewData) {
        if (viewData instanceof ViewData.TerminalErrorViewData) {
            showResultOverlay(false,
                    getString(R.string.overlay_error),
                    true);
            return;
        }

        if (viewData instanceof ViewData.SessionErrorViewData) {
            SessionActivationFailureCause cause =
                    ((ViewData.SessionErrorViewData) viewData).cause;
            if (cause == SessionActivationFailureCause.DEACTIVATED) {
                viewModel.disposeTerminal(true);
            } else {
                showResultOverlay(false, getString(R.string.overlay_error), true);
            }
            return;
        }

        if (viewData instanceof ViewData.TerminalNotCreatedViewData) {
            showProcessingOverlay(getString(R.string.overlay_initializing));
            viewModel.createTerminal();
            return;
        }

        if (viewData instanceof ViewData.TerminalInitialisingViewData) {
            showProcessingOverlay(getString(R.string.overlay_initializing));
            viewModel.initialise(new MainViewModel.TerminalInitialiseListener() {
                @Override
                public void onTerminalInitialised(Terminal terminal) {
                    runOnUiThread(() -> viewModel.activate());
                }

                @Override
                public void onTerminalInitialisedFailed(Throwable throwable) {
                    runOnUiThread(() -> {
                        viewModel.disposeTerminal(false);
                        showResultOverlay(false, getString(R.string.overlay_error), true);
                    });
                }
            });
            return;
        }

        if (viewData instanceof ViewData.TerminalReadyViewData) {
            showProcessingOverlay(getString(R.string.overlay_initializing));
            viewModel.activate();
            return;
        }

        if (viewData instanceof ViewData.TerminalActivatingViewData) {
            showProcessingOverlay(getString(R.string.overlay_initializing));
            return;
        }

        if (viewData instanceof ViewData.TerminalSessionTimeoutViewData) {
            showProcessingOverlay(getString(R.string.overlay_initializing));
            viewModel.reactivate((ViewData.TerminalSessionTimeoutViewData) viewData);
            return;
        }

        if (viewData instanceof ViewData.TerminalInSessionViewData) {
            // Terminal is ready — show the grid
            hideAllOverlays();
            return;
        }

        if (viewData instanceof ViewData.TerminalInProcessingViewData) {
            UiMessage uiMessage = ((ViewData.TerminalInProcessingViewData) viewData).uiMessage;
            String msg = uiMessage != null
                    ? uiMessage.getId().name().replace('_', ' ')
                    : getString(R.string.overlay_processing);
            showProcessingOverlay(msg);
            return;
        }

        if (viewData instanceof ViewData.DisplaySchemeHapticsViewData) {
            hideAllOverlays();
            playSchemeHaptics(((ViewData.DisplaySchemeHapticsViewData) viewData).cardScheme);
            return;
        }

        if (viewData instanceof ViewData.ProcessingFinishedViewData) {
            ViewData.ProcessingFinishedViewData finished =
                    (ViewData.ProcessingFinishedViewData) viewData;
            UiMessage uiMessage = finished.uiMessage;
            boolean approved = uiMessage != null
                    && uiMessage.getId().name().contains("APPROVED");
            String label = approved
                    ? getString(R.string.overlay_approved)
                    : getString(R.string.overlay_declined);
            showResultOverlay(approved, label, false);
        }
    }

    // ── Overlay helpers ──────────────────────────────────────────────

    private void showProcessingOverlay(String message) {
        processingMessage.setText(message);
        processingOverlay.setVisibility(View.VISIBLE);
        resultOverlay.setVisibility(View.GONE);
    }

    private void showResultOverlay(boolean approved, String message, boolean showRetry) {
        processingOverlay.setVisibility(View.GONE);
        resultOverlay.setVisibility(View.VISIBLE);
        resultIcon.setText(approved ? "✓" : "✕");
        resultIcon.setTextColor(getColor(approved
                ? R.color.softpos_success
                : R.color.softpos_error));
        resultMessage.setText(message);
        retryButton.setVisibility(showRetry ? View.VISIBLE : View.GONE);
        settingsButton.setVisibility(showRetry ? View.VISIBLE : View.GONE);
    }

    private void hideResultOverlay() {
        resultOverlay.setVisibility(View.GONE);
    }

    private void hideAllOverlays() {
        processingOverlay.setVisibility(View.GONE);
        resultOverlay.setVisibility(View.GONE);
    }

    private void playSchemeHaptics(CardScheme cardScheme) {
        schemeHapticsAnimationView.setVisibility(View.VISIBLE);
        schemeHapticsAnimationView.play(cardScheme, null, null, (v) -> {
            v.setVisibility(View.GONE);
            viewModel.schemeHapticsFinished();
            return null;
        });
    }
}
