package jesse.keeblarcraft.BankMgr;

import java.util.List;

import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;

// Contains the information of an individuals player's bank account.
// TODO: Add ability to store NBT data of items in the future so we can store not just money but items too
// like a safety deposit box
public class IndividualAccount {
    private String globalAccountNumber;
    private String bankLetterIdentifier;
    private String accountNumber;
    private String accountNumberAlias;
    private Integer routingNumber; // Will always be the bank it's in
    private List<String> accountHolders;
    private List<String> accountHolderUuids;
    private Integer accountBalance;
    private Boolean allowNegativeBalance;
    private Boolean accountLocked;
    private ACCOUNT_TYPE accountType;


    public IndividualAccount() {}

    public IndividualAccount(String accountNumber, Integer routingNumber, List<String> holders,
                            List<String> accountHolderUuids, Boolean allowNegativeBalance, Integer initialBalance,
                            String alias, ACCOUNT_TYPE accountType, String bankLetterIdentifier) {

        System.out.println("Called to create new IndividualAccount with following values: " + accountNumber + " " + routingNumber + " " + holders + " " +
        accountHolderUuids + " " + allowNegativeBalance + " " + initialBalance + " " + alias + " " + accountType);
        this.accountNumber = accountNumber;
        this.routingNumber = routingNumber;
        this.accountHolders = holders;
        this.accountHolderUuids = accountHolderUuids;
        this.allowNegativeBalance = allowNegativeBalance;
        this.accountBalance = initialBalance;
        this.accountNumberAlias = alias;
        this.accountType = accountType;
        this.bankLetterIdentifier = bankLetterIdentifier;
        this.globalAccountNumber = bankLetterIdentifier + "-" + routingNumber + "-" + accountNumber;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         AddAccountHolder
    ///
    /// @param[in]  newHolder to be added to account
    ///
    /// @param[in]  newHolderUuid to be added to account
    ///
    /// @brief      Adds another UUID who can access the bank account
    /////////////////////////////////////////////////////////////////////////////
    public void AddAccountHolder(String newHolder, String newHolderUuid) {
        if (!accountHolders.contains(newHolder)) {
            accountHolders.add(newHolder);
        }

        if (!accountHolderUuids.contains(newHolderUuid)) {
            accountHolderUuids.add(newHolderUuid);
        }
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         SetMoney
    ///
    /// @param[in]  amount is the new account balance
    ///
    /// @brief      Set the balance of the bank account. NOT RECOMMENDED OUTSIDE
    ///             OF ADMINISTRATIVE USE!!!
    ///
    /// @note       This will forcefully ignore account settings like not being
    ///             able to go negative. This is not recommended to use
    /////////////////////////////////////////////////////////////////////////////
    public void SetMoney(Integer amount) {
        System.out.println("Previous balance on account: " + this.accountBalance + ". New balance: " + amount);
        this.accountBalance = amount;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         AliasAccount
    ///
    /// @param[in]  newAlias to name the account
    ///
    /// @brief      Sets new alias of this account
    /////////////////////////////////////////////////////////////////////////////
    public void AliasAccount(String newAlias) {
        this.accountNumberAlias = newAlias;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         IsLocked
    ///
    /// @brief      Returns if account is locked
    ///
    /// @return     True if locked, false if not
    /////////////////////////////////////////////////////////////////////////////
    public Boolean IsLocked() {
        return accountLocked;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         LockAccount
    ///
    /// @brief      Locks an account
    /////////////////////////////////////////////////////////////////////////////
    public void LockAccount() {
        accountLocked = true;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         Deposit
    ///
    /// @param[in]  amount is amount to be added
    ///
    /// @brief      Deposits (adds) amount of money to account
    ///
    /// @return     True if succeeds, false if fails
    /////////////////////////////////////////////////////////////////////////////
    public Boolean Deposit(Integer amount) {
        Boolean success = false;
        if (!accountLocked)
        {
            accountBalance += amount;
            success = true;
        }

        return success;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         Withdraw
    ///
    /// @param[in]  amount is amount to be subtracted
    ///
    /// @brief      Withdraws (subtracts) amount from account balance
    ///
    /// @return     True if succeeds, false if fails
    /////////////////////////////////////////////////////////////////////////////
    public Boolean Withdraw(Integer amount) {
        Boolean success = false;

        if (!accountLocked)
        {
            // Determine remaining balance
            Integer remaining = accountBalance - amount;
            success = (remaining < 0 && !allowNegativeBalance);

            // Complete the transaction if successful
            if (success) {
                accountBalance = remaining;
            }
        }
        return success;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         CanWithdraw
    ///
    /// @return     True if account can afford withdrawal, false if not
    /////////////////////////////////////////////////////////////////////////////
    public Boolean CanWithdraw(Integer amount) {
        Boolean canWithdraw = false;

        if (!accountLocked && (accountBalance - amount >= 0 || allowNegativeBalance)) {
            canWithdraw = true;
        }

        return canWithdraw;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         IsHolder
    ///
    /// @return     True if name is on name list
    /////////////////////////////////////////////////////////////////////////////
    public Boolean IsHolder(String name) {
        Boolean ret = false;

        if (accountHolders.contains(name)) {
            ret = true;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         AllowsNegative
    ///
    /// @return     True if account allows negative balances, false if not
    /////////////////////////////////////////////////////////////////////////////
    public Boolean AllowsNegative() {
        return this.allowNegativeBalance;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         GetAccountHolders
    ///
    /// @return     List of everyone who has access to this account
    /////////////////////////////////////////////////////////////////////////////
    public List<String> GetAccountHolders() {
        return accountHolders;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         GetAccountBalance
    ///
    /// @return     Account balance
    /////////////////////////////////////////////////////////////////////////////
    public Integer GetAccountBalance() {
        return accountBalance;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         GetAccountNumber
    ///
    /// @return     String representation of account number (SHORT account number)
    /////////////////////////////////////////////////////////////////////////////
    public String GetAccountNumber() {
        return accountNumber;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         GetRoutingNumber
    ///
    /// @return     Routing number of account
    /////////////////////////////////////////////////////////////////////////////
    public Integer GetRoutingNumber() {
        return routingNumber;
    }

    /////////////////////////////////////////////////////////////////////////////
    /// @fn         GetGlobalAccountNumber
    ///
    /// @return     Gets global (ENTIRE) account number
    /////////////////////////////////////////////////////////////////////////////
    public String GetGlobalAccountNumber() {
        return globalAccountNumber;
    }
}
