package extractcommand.step05;

import extractcommand.step00.*;
import extractcommand.AtmCommand;

public class AtmSession {

    AccountService accountService;
    Logger logger;

    public AtmSession(AccountService accountService, Logger logger) {
        this.accountService = accountService;
        this.logger = logger;
    }

    // * Inject fields
    public User checkOwner(final int accountNumber) throws SessionException {
        return new CheckOwner(logger, accountService, accountNumber).execute();
    }

    public Money checkBalance(int accountNumber) throws SessionException {
        try {
            Account account = accountService.findAccount(accountNumber);
            Money balance = account.getBalance();
            return balance;
        }
        catch (AccountServiceException e) {
            logger.log(e);
            throw new SessionException(e);
        }
    }

    public Money deposit(int accountNumber, Money amount) throws SessionException {
        try {
            Account account = accountService.findAccount(accountNumber);
            account.deposit(amount);
            return account.getBalance();
        }
        catch (AccountServiceException e) {
            logger.log(e);
            throw new SessionException(e);
        }
    }

    public Money withdraw(int accountNumber, Money amount) throws SessionException {
        try {
            Account account = accountService.findAccount(accountNumber);
            verifyBalance(account, amount);
            account.withdraw(amount);
            return account.getBalance();
        }
        catch (AccountServiceException e) {
            logger.log(e);
            throw new SessionException(e);
        }
    }

    public void transfer(int fromAccountNumber, int toAccountNumber, Money amount) throws SessionException {
        try {
            Account fromAccount = accountService.findAccount(fromAccountNumber);
            Account toAccount = accountService.findAccount(toAccountNumber);
            verifyBalance(fromAccount, amount);
            fromAccount.withdraw(amount);
            toAccount.deposit(amount);
        }
        catch (AccountServiceException e) {
            logger.log(e);
            throw new SessionException(e);
        }
    }

    private void verifyBalance(Account account, Money amount) throws SessionException {
        Money balance = account.getBalance();
        if (balance.subtract(amount).isNegative()) {
            throw new SessionException("Insufficient funds");
        }
    }

    // * Convert class to static (type "st" Ctl-Space)
    // * Observe red squigglies
    // * Introduce Field (Ctl-W, Ctl-Alt-F)
    // ** Initialized in constructor
    // ** Ignore "duplicate name" warning
    // * Fix "x = x" -> "this.x = x"
    // * Introduce Parameter (Ctl-W, Ctl-Alt-P)
    private static class CheckOwner extends AtmCommand<User> {
        private AccountService accountService;
        private final int accountNumber;

        public CheckOwner(Logger logger, AccountService accountService, int accountNumber) {
            super(logger);
            this.accountService = accountService;
            this.accountNumber = accountNumber;
        }

        protected User doExecute() throws AccountServiceException {
            User result;
            Account account = accountService.findAccount(accountNumber);
            result = account.getOwner();
            return result;
        }
    }
}

