package CipherCracker;

import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.util.SystemFileChooser;
import java.io.File;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import javax.swing.*;
import java.awt.*;

public class Main {
    private static String keyFilePath = "";
    private static String checkFilePath = "";
    public static void main(String[] args) {

        // Sets the program up
        ConverterHelpers.mapBuilder();
        FlatDarkLaf.setup();


        // Set up the FlatLaF Look and Feel
        try {
            UIManager.setLookAndFeel(new FlatDarkLaf());
        } catch (Exception ex) {
            System.err.println("Failed to initialize FlatLaF");
        }

        // Create and display the GUI
        SwingUtilities.invokeLater(() -> {
            // Defines the JPanels, variables, and other stuff
            JFrame frame = new JFrame("Cipher Cracker");
            JPanel rightMenuButtons = new JPanel(new GridBagLayout());
            JPanel bottomMenuButtons = new JPanel(new BorderLayout());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(600, 400);
            frame.setLayout(new BorderLayout(10, 10));
            int uniformWidth = 115;

            // Text Entry
            JTextArea textEntry = new JTextArea();
            textEntry.setLineWrap(true);
            textEntry.setWrapStyleWord(true);
            JScrollPane scrollPane = new JScrollPane(textEntry);
            textEntry.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            frame.add(new JLabel("Welcome to TBCipherToolkit-XG!", SwingConstants.CENTER), BorderLayout.NORTH);
            frame.add(scrollPane, BorderLayout.CENTER);

            // Text
            JLabel keyFilePathLabel = new JLabel("Key File Path:  None Selected");
            JLabel checkFilePathLabel = new JLabel("Check File Path:  None Selected");

            // Buttons
            JButton decryptButton = new JButton("Run Decryption");
            JButton keyFileButton = new JButton("Select key file");
            JButton checkFileButton = new JButton("Select check file");

            // Sets the alignment in the center of the rightMenuButtons
            keyFileButton.setAlignmentX(Component.CENTER_ALIGNMENT);
            checkFileButton.setAlignmentX(Component.CENTER_ALIGNMENT);

            // The listeners for the buttons to make them actually do something
            keyFileButton.addActionListener(e -> {
                String file = selectFile();
                if (file != null) {
                    keyFilePath = file;
                    keyFilePathLabel.setText("Key file path: "+file);
                }
            });
            checkFileButton.addActionListener(e -> {
                String file = selectFile();
                if (file != null) {
                    checkFilePath = file;
                    checkFilePathLabel.setText("Check file path: "+file);
                }
            });
            decryptButton.addActionListener(e -> {
                if (keyFilePath.isEmpty()) {
                    flashLabel(keyFilePathLabel);
                    return;
                }
                if (checkFilePath.isEmpty()) {
                    flashLabel(checkFilePathLabel);
                    return;
                }
                String cipherText = textEntry.getText();
                if (cipherText.isEmpty()) {
                    failurePopup("EMPTY_CIPHER_TEXT");
                    return;
                }
                String foundKey = PrimaryCracker.cracker(checkFilePath,  keyFilePath, cipherText);
                if (foundKey != null) {
                    if (!foundKey.isEmpty()) {
                        String decryptedMessage = PrimaryDecryptor.decrypt(cipherText, foundKey);
                        copyToClipboardPopup(decryptedMessage, foundKey);
                    } else {
                        failurePopup("KEY_NOT_FOUND");
                    }
                } else {
                    failurePopup("KEY_IS_NULL");
                }
                System.gc(); // Frees up memory after cracking
            });

            // Makes the layout look better
            rightMenuButtons.setLayout(new BoxLayout(rightMenuButtons, BoxLayout.Y_AXIS));
            rightMenuButtons.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
            keyFileButton.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, uniformWidth);
            checkFileButton.putClientProperty(FlatClientProperties.MINIMUM_WIDTH, uniformWidth);

            // Adds the buttons
            rightMenuButtons.add(keyFileButton);
            rightMenuButtons.add(Box.createRigidArea(new Dimension(0, 10)));
            rightMenuButtons.add(checkFileButton);

            // Manages the text at the bottom of the panel
            JPanel textPanel = new JPanel();
            textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.Y_AXIS));
            textPanel.add(keyFilePathLabel, BorderLayout.NORTH);
            textPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            textPanel.add(checkFilePathLabel,BorderLayout.SOUTH);

            // Bottom panel buttons and text
            bottomMenuButtons.add(textPanel, BorderLayout.NORTH);
            bottomMenuButtons.add(decryptButton, BorderLayout.SOUTH);

            // Completes the JFrame
            frame.setLocationRelativeTo(null);
            frame.add(rightMenuButtons, BorderLayout.EAST);
            frame.add(bottomMenuButtons, BorderLayout.SOUTH);
            frame.setVisible(true);
        });
    }


    private static String selectFile() {
        SystemFileChooser fileChooser = new SystemFileChooser();
        fileChooser.addChoosableFileFilter(
                new SystemFileChooser.FileNameExtensionFilter("Text Files", "txt")
        );
        if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            return selectedFile.getAbsolutePath();
        }
        return null;
    }

    public static void copyToClipboard(String text) {
        // 1. Get the system clipboard
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();

        // 2. Wrap the text in a StringSelection object
        StringSelection selection = new StringSelection(text);

        // 3. Set the clipboard contents
        // The second parameter is the 'owner' of the clipboard data, which can be null
        clipboard.setContents(selection, null);
    }

    public static void copyToClipboardPopup(String cleanText, String key) {
        // Copy text to clipboard popup
        String messageBuilder = "Cipher Cracked!\nDecrypted Text: " + cleanText +"\nKey: " + key;
        Object[] options = {"Copy decrypted text", "Copy key", "Close"};


        int choice = JOptionPane.showOptionDialog(null, messageBuilder, "Cipher Cracked!", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, null);

        if (choice == 0) {
            copyToClipboard(cleanText);
        } else if (choice == 1) {
            copyToClipboard(key);
        }
    }

    public static void failurePopup(String errorMessage) {
        JOptionPane.showMessageDialog(null, "Unfortunately, the cipher cracker could not crack your message. \nPlease check your cipher text and try again.\n\nError code: "+errorMessage, "Cipher Cracker Failed!", JOptionPane.ERROR_MESSAGE);
    }

    public static void flashLabel(JLabel label) {
        int delay = 150;
        String normalColor = "foreground: #DDDDDD";
        String alertColor = "foreground: #FF6B6B";
        final boolean[] isAlertColor = {false};

        Timer timer = new Timer(delay, e -> {
            if (isAlertColor[0]) {
                label.putClientProperty(FlatClientProperties.STYLE, normalColor);
            } else {
                label.putClientProperty(FlatClientProperties.STYLE, alertColor);
            }
            isAlertColor[0] = !isAlertColor[0];
        });
        timer.start();
        new Timer(750, arg -> timer.stop()).start();
    }
}
