package net.viper.bceconomy;

import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.OfflinePlayer;

import java.util.List;
import java.util.UUID;

/**
 * Vault Economy-Implementierung.
 * Jeder Aufruf geht direkt in die DB – kein Cache.
 */
public class BCEconomyProvider implements Economy {

    private final BCDatabase db;
    private final String     currencyName;
    private final String     currencyNamePlural;
    private final double     startBalance;
    private final int        decimals;

    public BCEconomyProvider(BCDatabase db, String currencyName,
                              String currencyNamePlural,
                              double startBalance, int decimals) {
        this.db                = db;
        this.currencyName      = currencyName;
        this.currencyNamePlural = currencyNamePlural;
        this.startBalance      = startBalance;
        this.decimals          = decimals;
    }

    // ────────────────────────────────────────────────
    //  Meta
    // ────────────────────────────────────────────────

    @Override public boolean isEnabled()              { return db.isConnected(); }
    @Override public String  getName()                { return "BCEconomy"; }
    @Override public boolean hasBankSupport()         { return false; }
    @Override public int     fractionalDigits()       { return decimals; }
    @Override public String  format(double amount)    {
        return String.format("%,." + decimals + "f " + currencyName, amount);
    }
    @Override public String  currencyNamePlural()     { return currencyNamePlural; }
    @Override public String  currencyNameSingular()   { return currencyName; }

    // ────────────────────────────────────────────────
    //  Account
    // ────────────────────────────────────────────────

    @Override
    public boolean hasAccount(OfflinePlayer player) {
        return db.hasAccount(player.getUniqueId());
    }

    @Override
    public boolean hasAccount(OfflinePlayer player, String world) {
        return hasAccount(player);
    }

    @Override
    public boolean createPlayerAccount(OfflinePlayer player) {
        db.createAccountIfAbsent(player.getUniqueId(), startBalance);
        if (player.getName() != null)
            db.saveNameMapping(player.getUniqueId(), player.getName());
        return true;
    }

    @Override
    public boolean createPlayerAccount(OfflinePlayer player, String world) {
        return createPlayerAccount(player);
    }

    // ────────────────────────────────────────────────
    //  Balance – direkt aus DB
    // ────────────────────────────────────────────────

    @Override
    public double getBalance(OfflinePlayer player) {
        double bal = db.loadBalance(player.getUniqueId());
        if (bal < 0) {
            // Neuer Spieler – Konto anlegen
            db.createAccountIfAbsent(player.getUniqueId(), startBalance);
            if (player.getName() != null)
                db.saveNameMapping(player.getUniqueId(), player.getName());
            return startBalance;
        }
        return bal;
    }

    @Override
    public double getBalance(OfflinePlayer player, String world) {
        return getBalance(player);
    }

    @Override
    public boolean has(OfflinePlayer player, double amount) {
        return getBalance(player) >= amount;
    }

    @Override
    public boolean has(OfflinePlayer player, String world, double amount) {
        return has(player, amount);
    }

    // ────────────────────────────────────────────────
    //  Deposit / Withdraw – direkt in DB
    // ────────────────────────────────────────────────

    @Override
    public EconomyResponse depositPlayer(OfflinePlayer player, double amount) {
        if (amount < 0)
            return new EconomyResponse(0, 0, EconomyResponse.ResponseType.FAILURE,
                    "Betrag darf nicht negativ sein.");

        double current = db.loadBalance(player.getUniqueId());
        if (current < 0) {
            db.createAccountIfAbsent(player.getUniqueId(), startBalance);
            current = startBalance;
        }
        double newBal = current + amount;
        db.saveBalance(player.getUniqueId(), newBal);
        return new EconomyResponse(amount, newBal, EconomyResponse.ResponseType.SUCCESS, null);
    }

    @Override
    public EconomyResponse depositPlayer(OfflinePlayer player, String world, double amount) {
        return depositPlayer(player, amount);
    }

    @Override
    public EconomyResponse withdrawPlayer(OfflinePlayer player, double amount) {
        if (amount < 0)
            return new EconomyResponse(0, 0, EconomyResponse.ResponseType.FAILURE,
                    "Betrag darf nicht negativ sein.");

        double current = db.loadBalance(player.getUniqueId());
        if (current < 0) current = 0;
        if (current < amount)
            return new EconomyResponse(amount, current, EconomyResponse.ResponseType.FAILURE,
                    "Nicht genug Guthaben.");

        double newBal = current - amount;
        db.saveBalance(player.getUniqueId(), newBal);
        return new EconomyResponse(amount, newBal, EconomyResponse.ResponseType.SUCCESS, null);
    }

    @Override
    public EconomyResponse withdrawPlayer(OfflinePlayer player, String world, double amount) {
        return withdrawPlayer(player, amount);
    }

    // ────────────────────────────────────────────────
    //  Deprecated String-Methoden (Vault-Kompatibilität)
    // ────────────────────────────────────────────────

    @Override @Deprecated
    public boolean hasAccount(String playerName) {
        UUID uuid = db.resolveUUIDByName(playerName);
        return uuid != null && db.hasAccount(uuid);
    }

    @Override @Deprecated
    public boolean hasAccount(String playerName, String world) { return hasAccount(playerName); }

    @Override @Deprecated
    public double getBalance(String playerName) {
        UUID uuid = db.resolveUUIDByName(playerName);
        if (uuid == null) return 0;
        double bal = db.loadBalance(uuid);
        return bal < 0 ? startBalance : bal;
    }

    @Override @Deprecated
    public double getBalance(String playerName, String world) { return getBalance(playerName); }

    @Override @Deprecated
    public boolean has(String playerName, double amount) { return getBalance(playerName) >= amount; }

    @Override @Deprecated
    public boolean has(String playerName, String world, double amount) { return has(playerName, amount); }

    @Override @Deprecated
    public EconomyResponse depositPlayer(String playerName, double amount) {
        UUID uuid = db.resolveUUIDByName(playerName);
        if (uuid == null)
            return new EconomyResponse(0, 0, EconomyResponse.ResponseType.FAILURE, "Spieler nicht gefunden.");
        double current = db.loadBalance(uuid);
        if (current < 0) current = 0;
        double newBal = current + amount;
        db.saveBalance(uuid, newBal);
        return new EconomyResponse(amount, newBal, EconomyResponse.ResponseType.SUCCESS, null);
    }

    @Override @Deprecated
    public EconomyResponse depositPlayer(String playerName, String world, double amount) {
        return depositPlayer(playerName, amount);
    }

    @Override @Deprecated
    public EconomyResponse withdrawPlayer(String playerName, double amount) {
        UUID uuid = db.resolveUUIDByName(playerName);
        if (uuid == null)
            return new EconomyResponse(0, 0, EconomyResponse.ResponseType.FAILURE, "Spieler nicht gefunden.");
        double current = db.loadBalance(uuid);
        if (current < 0) current = 0;
        if (current < amount)
            return new EconomyResponse(amount, current, EconomyResponse.ResponseType.FAILURE, "Nicht genug Guthaben.");
        double newBal = current - amount;
        db.saveBalance(uuid, newBal);
        return new EconomyResponse(amount, newBal, EconomyResponse.ResponseType.SUCCESS, null);
    }

    @Override @Deprecated
    public EconomyResponse withdrawPlayer(String playerName, String world, double amount) {
        return withdrawPlayer(playerName, amount);
    }

    @Override @Deprecated
    public boolean createPlayerAccount(String playerName) { return false; }

    @Override @Deprecated
    public boolean createPlayerAccount(String playerName, String world) { return false; }

    // ────────────────────────────────────────────────
    //  Bank (nicht unterstützt)
    // ────────────────────────────────────────────────

    @Override public EconomyResponse createBank(String name, String player)     { return notSupported(); }
    @Override public EconomyResponse createBank(String name, OfflinePlayer p)   { return notSupported(); }
    @Override public EconomyResponse deleteBank(String name)                     { return notSupported(); }
    @Override public EconomyResponse bankBalance(String name)                    { return notSupported(); }
    @Override public EconomyResponse bankHas(String name, double amount)         { return notSupported(); }
    @Override public EconomyResponse bankWithdraw(String name, double amount)    { return notSupported(); }
    @Override public EconomyResponse bankDeposit(String name, double amount)     { return notSupported(); }
    @Override public EconomyResponse isBankOwner(String name, String p)          { return notSupported(); }
    @Override public EconomyResponse isBankOwner(String name, OfflinePlayer p)   { return notSupported(); }
    @Override public EconomyResponse isBankMember(String name, String p)         { return notSupported(); }
    @Override public EconomyResponse isBankMember(String name, OfflinePlayer p)  { return notSupported(); }
    @Override public List<String> getBanks()                                     { return List.of(); }

    private EconomyResponse notSupported() {
        return new EconomyResponse(0, 0, EconomyResponse.ResponseType.NOT_IMPLEMENTED,
                "Banken werden nicht unterstützt.");
    }
}
