package dev.crucifixbeta.mod.auth;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;

@Environment(EnvType.CLIENT)
public final class RLGGAuthWindow {
    private static final AtomicBoolean OPENED = new AtomicBoolean();

    private RLGGAuthWindow() {
    }

    public static void requireVerified() {
        waitUntilVerified();
    }

    private static void waitUntilVerified() {
        if (RLGGAuthManager.isVerified()) {
            return;
        }
        if (GraphicsEnvironment.isHeadless()) {
            throw new IllegalStateException("CrucifiX authorization requires a desktop environment.");
        }
        if (!OPENED.compareAndSet(false, true)) {
            while (!RLGGAuthManager.isVerified() && OPENED.get()) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException exception) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
            return;
        }

        CountDownLatch latch = new CountDownLatch(1);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                lambda$requireVerified$0(latch);
            }
        });
        try {
            latch.await();
        } catch (InterruptedException exception) {
            Thread.currentThread().interrupt();
        } finally {
            OPENED.set(false);
        }
    }

    private static void lambda$requireVerified$0(CountDownLatch latch) {
        new AuthFrame(latch).open();
    }

    @Environment(EnvType.CLIENT)
    private static final class AuthFrame extends JFrame {
        private final CountDownLatch latch;
        private final JTextField cardKeyField = new JTextField();
        private final JLabel statusLabel = new JLabel("Enter your card key.", JLabel.CENTER);
        private final JCheckBox rememberBox = new JCheckBox("Remember card key", true);
        private final JButton loginButton = new JButton("Login");
        private final JButton unbindButton = new JButton("Unbind");

        private AuthFrame(CountDownLatch latch) {
            super("CrucifiX Authorization");
            this.latch = latch;
        }

        private void open() {
            setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            setResizable(false);
            setAlwaysOnTop(true);
            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent event) {
                    System.exit(0);
                }
            });

            JPanel root = new JPanel(new BorderLayout(0, 12));
            root.setBorder(BorderFactory.createEmptyBorder(18, 20, 18, 20));
            root.setBackground(new Color(24, 26, 31));
            setContentPane(root);

            statusLabel.setForeground(Color.WHITE);
            statusLabel.setFont(new Font("SansSerif", Font.BOLD, 14));
            statusLabel.setOpaque(false);
            root.add(statusLabel, BorderLayout.NORTH);

            JPanel form = new JPanel(new GridBagLayout());
            form.setOpaque(false);
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.gridx = 0;
            constraints.gridy = 0;
            constraints.weightx = 1.0;
            constraints.fill = GridBagConstraints.HORIZONTAL;
            constraints.insets = new Insets(4, 0, 4, 0);
            JLabel cardLabel = new JLabel("Card Key");
            cardLabel.setForeground(Color.WHITE);
            form.add(cardLabel, constraints);

            constraints.gridy++;
            cardKeyField.setPreferredSize(new Dimension(350, 30));
            cardKeyField.setText(RLGGAuthManager.getSavedCardKey());
            form.add(cardKeyField, constraints);

            constraints.gridy++;
            rememberBox.setOpaque(false);
            rememberBox.setForeground(Color.WHITE);
            form.add(rememberBox, constraints);
            root.add(form, BorderLayout.CENTER);

            JPanel buttons = new JPanel();
            buttons.setOpaque(false);
            buttons.add(loginButton);
            buttons.add(unbindButton);
            root.add(buttons, BorderLayout.SOUTH);

            loginButton.addActionListener(this::lambda$open$0);
            unbindButton.addActionListener(this::lambda$open$1);
            cardKeyField.addActionListener(this::lambda$open$2);

            if (RLGGAuthManager.isDevAccountDetected()) {
                statusLabel.setText("Dev test account.");
            }
            pack();
            setLocationRelativeTo(null);
            setVisible(true);
            cardKeyField.requestFocusInWindow();
            toFront();
        }

        private void login() {
            setBusy(true, "Verifying...");
            RLGGAuthManager.verifyAsync(cardKeyField.getText(), rememberBox.isSelected())
                    .whenComplete(this::lambda$login$4);
        }

        private void unbind() {
            setBusy(true, "Unbinding...");
            RLGGAuthManager.unbindAsync(cardKeyField.getText())
                    .whenComplete(this::lambda$unbind$6);
        }

        private void setBusy(boolean busy, String message) {
            cardKeyField.setEnabled(!busy);
            rememberBox.setEnabled(!busy);
            loginButton.setEnabled(!busy);
            unbindButton.setEnabled(!busy);
            statusLabel.setText(message == null ? "" : message);
        }

        private void lambda$unbind$6(RLGGAuthManager.VerifyResult result, Throwable throwable) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    lambda$unbind$5(throwable, result);
                }
            });
        }

        private void lambda$unbind$5(Throwable throwable, RLGGAuthManager.VerifyResult result) {
            if (throwable != null) {
                setBusy(false, throwable.getMessage());
                return;
            }
            setBusy(false, result == null ? "" : result.message());
        }

        private void lambda$login$4(RLGGAuthManager.VerifyResult result, Throwable throwable) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    lambda$login$3(throwable, result);
                }
            });
        }

        private void lambda$login$3(Throwable throwable, RLGGAuthManager.VerifyResult result) {
            if (throwable != null) {
                setBusy(false, throwable.getMessage());
                return;
            }
            if (result != null && result.success()) {
                dispose();
                latch.countDown();
                return;
            }
            setBusy(false, result == null ? "" : result.message());
        }

        private void lambda$open$2(java.awt.event.ActionEvent event) {
            login();
        }

        private void lambda$open$1(java.awt.event.ActionEvent event) {
            unbind();
        }

        private void lambda$open$0(java.awt.event.ActionEvent event) {
            login();
        }
    }
}
