package dev.banking.model;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class BankAccount {

    private final int accountId;
    private long balance;

    // تعریف ReadWriteLock برای مدیریت همزمان خواندن و نوشتن بدون بلاک شدن اضافی
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

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

    public int getAccountId() {
        return accountId;
    }

    /*
     * گرفتن موجودی به صورت ترد-ایمن.
     * از readLock استفاده کردم تا چندتا ترد بتونن همزمان بدون معطل کردن هم، بالانس رو بخونن.
     */
    public long getBalance() {
        rwLock.readLock().lock();
        try {
            return balance;
        } finally {
            rwLock.readLock().unlock();
        }
    }

    /*
     * واریز پول به حساب به صورت اتمیک.
     * اینجا چون مقدار تغییر میکنه حتماً باید writeLock بگیریم تا دیتا خراب نشه.
     */
    public void deposit(long amount) {
        rwLock.writeLock().lock();
        try {
            balance += amount;
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    /*
     * برداشت پول از حساب به صورت اتمیک.
     * طبق داک فاز اول، منفی شدن بالانس مشکلی نداره و نیازی به چک کردن موجودی نیست.
     */
    public void withdraw(long amount) {
        rwLock.writeLock().lock();
        try {
            balance -= amount;
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    /*
     * انتقال پول بین دوتا حساب به صورت کاملاً اتمیک و بدون ددلاک.
     * برای اینکه ددلاک پیش نیاد، حساب‌ها رو بر اساس accountId مرتب میکنیم و همیشه قفل اونی که آیدی کمتری داره رو اول میگیریم.
     */
    public void transfer(BankAccount target, long amount) {
        // پیدا کردن ترتیب ثابت برای قفل گذاری بر اساس ID حساب‌ها
        BankAccount first = this.accountId < target.getAccountId() ? this : target;
        BankAccount second = this.accountId < target.getAccountId() ? target : this;

        // گرفتن قفل حساب اول
        first.rwLock.writeLock().lock();
        try {
            // گرفتن قفل حساب دوم
            second.rwLock.writeLock().lock();
            try {
                // حالا که قفل هردو حساب رو داریم، با خیال راحت انتقال رو انجام میدیم
                this.balance -= amount;
                target.balance += amount;
            } finally {
                // باز کردن قفل حساب دوم
                second.rwLock.writeLock().unlock();
            }
        } finally {
            // باز کردن قفل حساب اول
            first.rwLock.writeLock().unlock();
        }
    }
}