package me.teridax.jcash.gui.transfer;

import me.teridax.jcash.Logging;
import me.teridax.jcash.Main;
import me.teridax.jcash.banking.accounts.Account;
import me.teridax.jcash.banking.accounts.CurrentAccount;
import me.teridax.jcash.banking.management.BankingManagementSystem;
import me.teridax.jcash.gui.InvalidInputException;
import me.teridax.jcash.gui.Utils;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.text.ParseException;

/**
 * Dialog class for transferring some value from one account to another
 */
public class TransferController {

    private final Account account;
    private final TransferData transferData;
    private final TransferView view;

    public TransferController(Account account, BankingManagementSystem bms) {
        this.account = account;

        var overdraft = 0.0;
        if (account instanceof CurrentAccount) {
            overdraft += ((CurrentAccount) account).getOverdraft();
        }

        this.view = new TransferView(account.getBalance() + overdraft);
        this.transferData = new TransferData(bms);
        this.view.getTransfer().addActionListener(e -> transfer());
        this.view.getCancel().addActionListener(e -> view.dispose());

        // validates the users input
        var validator = new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent documentEvent) {
                validateInputState();
            }

            @Override
            public void removeUpdate(DocumentEvent documentEvent) {
                validateInputState();
            }

            @Override
            public void changedUpdate(DocumentEvent documentEvent) {
                validateInputState();
            }
        };

        this.view.getValue().getDocument().addDocumentListener(validator);
        this.view.getIbanTextField().getDocument().addDocumentListener(validator);
        this.view.getBlzTextField().getDocument().addDocumentListener(validator);

        this.view.showDialog();
    }

    /**
     * Returns true if the target bank account is valid.
     * @return  true if the target bank account is valid false otherwise
     */
    private boolean validateTargetAccount() {
        if (transferData.validateBLZ(this.view.getBlz())) {
            return transferData.validateIBAN(this.view.getBlz(), view.getIban());
        }
        return false;
    }

    /**
     * Returns true if the entered value to transfer is valid.
     * This method will also commit the valid value back to the text field.
     * @return true if the value to transfer is valid, false otherwise
     */
    private boolean validateTransferValue() {
        var balance = account.getBalance();
        try {
            view.getValue().commitEdit();
            var amount = view.getAmount();
            view.setCommittedValue(amount, balance - amount);
            return true;
        } catch (InvalidInputException | ParseException ex) {
            view.setCommittedValue(0, balance);
            return false;
        }
    }

    private void validateInputState() {
        var valid = validateTargetAccount() && validateTransferValue();
        view.getTransfer().setEnabled(valid);
    }

    /**
     * Attempts to transfer the balance from one account to another
     * This method will close the dialog.
     */
    private void transfer() {
        try {
            var amount = view.getAmount();
            this.account.takeoff(amount);
            this.transferData.transferValue(amount, view.getBlz(), view.getIban());
        } catch (IllegalArgumentException | InvalidInputException ex) {
            Logging.LOGGER.severe("Could not transfer: " + ex.getMessage());
            Utils.error("Reason: " + ex.getMessage());
        }
        this.view.dispose();
    }
}
