package btdex.ui;

import static btdex.locale.Translation.tr;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import btdex.core.BurstNode;
import btdex.core.Constants;
import btdex.core.Globals;
import btdex.core.Market;
import btdex.core.NumberFormatting;
import btdex.ledger.LedgerService;
import btdex.ledger.LedgerService.SignCallBack;
import burst.kit.entity.BurstAddress;
import burst.kit.entity.BurstID;
import burst.kit.entity.BurstValue;
import burst.kit.entity.response.FeeSuggestion;
import burst.kit.entity.response.TransactionBroadcast;
import io.reactivex.Single;

public class SendDialog extends JDialog implements ActionListener, SignCallBack {
	private static final long serialVersionUID = 1L;

	private JTextField recipient;
	private JTextField message;
	private JTextField amount;
	private JTextField ledgerStatus;
	private byte[] unsigned;
	private JPasswordField pin;
	private JSlider fee;
	private BurstValue selectedFee;

	private JButton okButton;

	private JButton calcelButton;

	private Market token;

	public SendDialog(JFrame owner, Market token) {
		super(owner, ModalityType.APPLICATION_MODAL);
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		
		this.token = token;

		setTitle(tr("main_send", token==null ? "BURST" : token));

		JPanel topPanel = new JPanel(new GridLayout(0, 1, 4, 4));

		JPanel panel = new JPanel(new GridLayout(0, 2, 4, 4));

		recipient = new JTextField(26);
		message = new JTextField(26);

		pin = new JPasswordField(12);
		pin.addActionListener(this);

		amount = new JFormattedTextField(token==null ? NumberFormatting.BURST.getFormat() : token.getNumberFormat().getFormat());
		fee = new JSlider(1, 4);

		topPanel.add(new Desc(tr("send_recipient"), recipient));
		topPanel.add(new Desc(tr("send_message"), message));
		message.setToolTipText(tr("send_empty_for_no_message"));

		panel.add(new Desc(tr("send_amount", token==null ? "BURST" : token), amount));
		Desc feeDesc = new Desc("", fee);
		panel.add(feeDesc);
		FeeSuggestion suggestedFee = BurstNode.getInstance().getSuggestedFee();
		
		fee.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent evt) {
				String feeType;
				switch (fee.getValue()) {
				case 1:
					feeType = tr("fee_minimum");
					selectedFee = BurstValue.fromPlanck(Constants.FEE_QUANT);
					break;
				case 2:
					feeType = tr("fee_cheap");
					selectedFee = suggestedFee.getCheapFee();
					break;
				case 3:
					feeType = tr("fee_standard");
					selectedFee = suggestedFee.getStandardFee();
					break;
				default:
					feeType = tr("fee_priority");
					selectedFee = suggestedFee.getPriorityFee();
					break;
				}
				feeDesc.setDesc(tr("send_fee", feeType, selectedFee.toUnformattedString()));
			}
		});

		// Create a button
		JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));

		calcelButton = new JButton(tr("dlg_cancel"));
		okButton = new JButton(tr("dlg_ok"));

		calcelButton.addActionListener(this);
		okButton.addActionListener(this);

		if(Globals.getInstance().usingLedger()) {
			ledgerStatus = new JTextField(26);
			ledgerStatus.setEditable(false);
			buttonPane.add(new Desc(tr("ledger_status"), ledgerStatus));
			LedgerService.getInstance().setCallBack(this);
		}
		else
			buttonPane.add(new Desc(tr("dlg_pin"), pin));
		buttonPane.add(new Desc(" ", calcelButton));
		buttonPane.add(new Desc(" ", okButton));

		// set action listener on the button

		JPanel content = (JPanel)getContentPane();
		content.setBorder(new EmptyBorder(4, 4, 4, 4));

		content.add(topPanel, BorderLayout.PAGE_START);
		content.add(panel, BorderLayout.CENTER);
		content.add(buttonPane, BorderLayout.PAGE_END);

		pack();

		fee.getModel().setValue(4);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == calcelButton) {
			setVisible(false);
		}
		if(e.getSource() == okButton || e.getSource() == pin) {
			Globals g = Globals.getInstance();

			String error = null;
			String sadd = recipient.getText();
			BurstID recID = null;
			if(sadd.startsWith("BURST-")) {
				try {
					recID = Globals.BC.rsDecode(sadd.substring(5));
				}
				catch (Exception ex) {
				}
			}
			if(recID == null)
				error = tr("send_invalid_recipient");

			if(error == null && !g.usingLedger() && !g.checkPIN(pin.getPassword())) {
				error = tr("dlg_invalid_pin");
				pin.requestFocus();
			}
			
			String msg = null;
			if(message.getText().length()>0)
				msg = message.getText();

			Number amountNumber = null;
			if(error == null) {
				try {
					amountNumber = NumberFormatting.parse(amount.getText());
				} catch (ParseException e1) {
					amount.requestFocus();
					error = tr("send_invalid_amount");
				}
			}

			if(error!=null) {
				Toast.makeText((JFrame) this.getOwner(), error, Toast.Style.ERROR).display(okButton);
			}
			else {
				setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

				try {
					// all set, lets make the transfer
					Single<byte[]> utx = null;
					if(token!=null) {
						utx = g.getNS().generateTransferAssetTransactionWithMessage(g.getPubKey(), BurstAddress.fromId(recID),
								token.getTokenID(), BurstValue.fromPlanck((long)(amountNumber.doubleValue()*token.getFactor())),
								selectedFee, Constants.BURST_DEADLINE, msg);
					}
					else {
						utx = g.getNS().generateTransactionWithMessage(BurstAddress.fromId(recID), g.getPubKey(),
							BurstValue.fromBurst(amountNumber.doubleValue()),
							selectedFee, Constants.BURST_DEADLINE, msg);
					}
					
					unsigned = utx.blockingGet();
					if(g.usingLedger()) {
						LedgerService.getInstance().requestSign(unsigned, null, g.getLedgerIndex());
						okButton.setEnabled(false);
						recipient.setEnabled(false);
						message.setEnabled(false);
						amount.setEnabled(false);
						fee.setEnabled(false);
						
						Toast.makeText((JFrame) this.getOwner(), tr("ledger_authorize"), Toast.Style.NORMAL).display(okButton);
						
						return;
					}
					byte[] signedTransactionBytes = g.signTransaction(pin.getPassword(), unsigned);
					reportSigned(signedTransactionBytes, null);
				}
				catch (Exception ex) {
					Toast.makeText((JFrame) this.getOwner(), ex.getCause().getMessage(), Toast.Style.ERROR).display(okButton);
				}
				setCursor(Cursor.getDefaultCursor());
			}
		}
	}

	@Override
	public void ledgerStatus(String txt) {
		ledgerStatus.setText(txt);
		ledgerStatus.setCaretPosition(0);
	}

	@Override
	public void reportSigned(byte[] signed, byte[] signed2) {
		if(!isVisible())
			return; // already closed by cancel, so we will not broadcast anyway
		
		if(signed == null) {
			// when coming from the hardware wallet
			okButton.setEnabled(true);
			recipient.setEnabled(true);
			message.setEnabled(true);
			amount.setEnabled(true);
			fee.setEnabled(true);

			setCursor(Cursor.getDefaultCursor());
			
			Toast.makeText((JFrame) this.getOwner(), tr("ledger_denied"), Toast.Style.ERROR).display(okButton);
			
			return;
		}
		TransactionBroadcast tb = Globals.getInstance().getNS().broadcastTransaction(signed).blockingGet();
		setVisible(false);

		Toast.makeText((JFrame) this.getOwner(),
				tr("send_tx_broadcast", tb.getTransactionId().toString()), Toast.Style.SUCCESS).display();
	}
}