package dev.banking.model;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class BankAccount
{
    private final int accountId;
    private long balance;

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition sufficientFunds = lock.newCondition();

    public BankAccount(int accountId, long initialBalance)
    {
        this.accountId = accountId;
        this.balance = initialBalance;
    }

    public int getAccountId() {return accountId;}

    public long getBalance()
    {
        lock.lock();
        try {return balance;}
        finally {lock.unlock();}
    }

    public void deposit(long amount)
    {
        lock.lock();
        try
        {
            balance += amount;
            sufficientFunds.signalAll(); // wake waiting threads
        }
        finally {lock.unlock();}
    }

    public void withdraw(long amount)
    {
        lock.lock();
        try
        {
            while (balance < amount) {sufficientFunds.await();}
            balance -= amount;
        }
        catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }
        finally {lock.unlock();
        }
    }

    public void transfer(BankAccount target, long amount)
    {
        if (this == target) return;

        BankAccount first = this.accountId < target.accountId ? this : target;
        BankAccount second = this.accountId < target.accountId ? target : this;

        first.lock.lock();
        second.lock.lock();

        try
        {
            while (this.balance < amount) {this.sufficientFunds.await();}

            this.balance -= amount;
            target.balance += amount;

            this.sufficientFunds.signalAll();
            target.sufficientFunds.signalAll();

        }
        catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }
        finally
        {
            second.lock.unlock();
            first.lock.unlock();
        }
    }
}