package fucoin.gui;

import akka.actor.ActorSelection;
import fucoin.wallet.AbstractWallet;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Enumeration;

public class WalletGuiControlImpl implements WalletGuiControl {

    private DefaultListModel<LogMessage> log = new DefaultListModel<>();

    private JFrame window = new JFrame("test");
    private JPanel topPanel = new JPanel();
    private JTextField txtMyName = new JTextField("<MyName>");
    private JTextField txtMyAddress = new JTextField("<MyAddress>");
    private JLabel lblMyAmount = new JLabel("My FUCs: ");
    private JLabel txtMyAmount = new JLabel(" <MyFUCs>");
    private JPanel centerPanel = new JPanel();
    private JLabel lblSendTo = new JLabel("Send to:");
    private JComboBox<String> txtSendTo = new JComboBox<>();
    private JLabel lblSendAmount = new JLabel("Amount:");
    private JTextField txtSendAmount = new JTextField("");
    private JButton btnSend = new JButton("Send");
    private JButton btnSearch = new JButton("Search");
    private JButton btnStore = new JButton("Store");
    private JButton btnExit = new JButton("Exit");
    private JPanel bottomPanel = new JPanel();
    private JList<LogMessage> txtLog = new JList<>(log);
    private JScrollPane logPane = new JScrollPane(txtLog);
    private JCheckBox showDebug;

    public WalletGuiControlImpl(AbstractWallet wallet) {

        window.setSize(400, 600);
        window.setLayout(new GridLayout(3, 1));
        topPanel.setLayout(new GridLayout(2, 1));
        // Row 1
        JPanel row1 = new JPanel();
        row1.setLayout(new BoxLayout(row1, BoxLayout.PAGE_AXIS));

        txtMyName.setHorizontalAlignment(JTextField.CENTER);
        txtMyName.setBorder(BorderFactory.createEmptyBorder());
        txtMyName.setFont(txtMyName.getFont().deriveFont(18f).deriveFont(Font.BOLD));
        txtMyName.setEditable(false);
        txtMyName.setForeground(Color.WHITE);

        txtMyName.setText(wallet.getName());

        txtMyAddress.setHorizontalAlignment(JTextField.CENTER);
        txtMyAddress.setBorder(BorderFactory.createEmptyBorder());
        txtMyAddress.setEditable(false);
        txtMyAddress.setForeground(Color.WHITE);

        //setTint(new Color(123,94,167));
        setTint(new Color(54, 135, 56));

        row1.add(txtMyName);
        row1.add(txtMyAddress);
        topPanel.add(row1);
        // Row 2
        JPanel row2 = new JPanel(new GridBagLayout());
        Font fucFont = txtMyAmount.getFont().deriveFont(20f).deriveFont(Font.BOLD);
        lblMyAmount.setFont(fucFont);
        txtMyAmount.setFont(fucFont);
        row2.add(lblMyAmount);
        row2.add(txtMyAmount);
        topPanel.add(row2);
        window.add(topPanel);
        //<hr>
        centerPanel.setLayout(new GridLayout(4, 1));
        // Row 1
        JPanel centerup = new JPanel();
        centerup.setLayout(new BorderLayout());
        centerup.add(lblSendTo, BorderLayout.WEST);
        centerup.add(txtSendTo, BorderLayout.CENTER);
        centerPanel.add(centerup);

        JPanel centerup2 = new JPanel();
        centerup2.setLayout(new BorderLayout());
        JTextField sendToNewEdt = new JTextField();
        centerup2.add(sendToNewEdt, BorderLayout.CENTER);
        JButton addNewButton = new JButton("Add");
        addNewButton.addActionListener(e -> {
            ActorSelection selection = wallet.getContext().actorSelection(sendToNewEdt.getText());
            System.out.println(selection);
        });
        centerup2.add(addNewButton, BorderLayout.EAST);
        centerPanel.add(centerup2);

        // Row 2
        JPanel centerdown = new JPanel();
        centerdown.setLayout(new GridLayout(1, 3));
        centerdown.add(lblSendAmount);
        centerdown.add(txtSendAmount);
        centerdown.add(btnSend);
        centerPanel.add(centerdown);

        // Row 3
        JPanel centerdown2 = new JPanel();
        centerdown2.setLayout(new GridLayout(1, 3));
        centerdown2.add(btnSearch);
        centerdown2.add(btnStore);
        centerdown2.add(btnExit);
        centerPanel.add(centerdown2);
        window.add(centerPanel);


        bottomPanel.setLayout(new BorderLayout());

        showDebug = new JCheckBox("Show debug messages in transaction log");
        showDebug.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                txtLog.setModel(log);
            } else {
                updateFilteredLog();
            }
        });

        bottomPanel.add(showDebug, BorderLayout.NORTH);
        bottomPanel.add(logPane, BorderLayout.CENTER);

        window.add(bottomPanel);
        window.setVisible(true);

        btnSend.addActionListener(e -> {
            wallet.send(txtSendTo.getSelectedItem().toString(),
                    Integer.parseInt(txtSendAmount.getText()));
        });

        btnStore.addActionListener(e -> {

        });


        txtLog.setCellRenderer(new LogCellRenderer());

        // Disable currently unused controls that might be useful in the future
        addNewButton.setEnabled(false);
        btnStore.setEnabled(false);
        btnSearch.setEnabled(false);
        sendToNewEdt.setEditable(false);

        btnExit.addActionListener(e -> window.dispose());

        window.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("window closing");
                wallet.leave();
                super.windowClosing(e);

            }

            @Override
            public void windowClosed(WindowEvent e) {
                System.out.println("window closing");
                wallet.leave();
                super.windowClosing(e);
            }
        });
    }

    /**
     * Set the color of the top section
     *
     * @param color The color used for the upper row. The color for the bottom row is calculated by lightening up the provided color
     */
    private void setTint(Color color) {
        txtMyName.setBackground(color);

        // Make the secondary color roughly 15% lighter
        float amount = 0.15f;

        int red = (int) ((color.getRed() * (1 - amount) / 255 + amount) * 255);
        int green = (int) ((color.getGreen() * (1 - amount) / 255 + amount) * 255);
        int blue = (int) ((color.getBlue() * (1 - amount) / 255 + amount) * 255);

        txtMyAddress.setBackground(new Color(red, green, blue));
    }

    @Override
    public void setAddress(String address) {
        txtMyAddress.setText(address);
        window.setTitle(address);
    }

    @Override
    public void setAmount(int amount) {
        txtMyAmount.setText(String.valueOf(amount));
    }

    @Override
    public void addKnownAddress(String address) {
        txtSendTo.addItem(address);
    }

    @Override
    public void addLogMsg(String msg) {
        log(new LogMessage(msg));
    }

    @Override
    public void addTransactionLogMessageSuccess(String message) {
        log(new LogMessage(message, LogMessage.Context.TRANSACTION_SUCCESS));
    }

    @Override
    public void addTransactionLogMessageFail(String message) {
        log(new LogMessage(message, LogMessage.Context.TRANSACTION_FAIL));
    }

    @Override
    public void setRemote() {
        setTint(new Color(45, 94, 167));
    }

    private void log(LogMessage logMessage) {
        SwingUtilities.invokeLater(() -> {
            log.addElement(logMessage);

            if (!showDebug.isSelected()) {
                updateFilteredLog();
            }

            // auto scroll to the bottom
            txtLog.ensureIndexIsVisible(log.size() - 1);
        });
    }

    private void updateFilteredLog() {

        DefaultListModel<LogMessage> filteredLog = new DefaultListModel<>();
        Enumeration<LogMessage> elements = log.elements();
        while (elements.hasMoreElements()) {
            LogMessage logMessage = elements.nextElement();
            LogMessage.Context context = logMessage.getContext();
            if (context == LogMessage.Context.TRANSACTION_FAIL || context == LogMessage.Context.TRANSACTION_SUCCESS) {
                filteredLog.addElement(logMessage);
            }
        }

        txtLog.setModel(filteredLog);
    }
}