package pt.henrique.communityMarket.economy;

import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.plugin.RegisteredServiceProvider;
import pt.henrique.communityMarket.CommunityMarket;

import java.util.UUID;
import java.util.logging.Level;

/**
 * Manages economy operations using Vault.
 * <p>
 * Vault provides a unified economy API that works with many economy plugins
 * including EssentialsX, CMI, and others.
 */
public class EconomyManager {

    private final CommunityMarket plugin;
    private Economy vaultEconomy;

    public EconomyManager(CommunityMarket plugin) {
        this.plugin = plugin;
    }

    /**
     * Attempts to set up the Vault economy provider.
     *
     * @return true if Vault economy was found
     */
    public boolean setupEconomy() {
        if (Bukkit.getPluginManager().getPlugin("Vault") == null) {
            plugin.getLogger().severe("Vault plugin not found!");
            return false;
        }

        try {
            RegisteredServiceProvider<Economy> rsp = Bukkit.getServicesManager().getRegistration(Economy.class);
            if (rsp == null) {
                plugin.getLogger().severe("No economy provider registered with Vault! Please install an economy plugin like EssentialsX.");
                return false;
            }

            vaultEconomy = rsp.getProvider();
            if (vaultEconomy != null) {
                plugin.getLogger().info("Using Vault economy provider: " + vaultEconomy.getName());
                return true;
            }
            return false;
        } catch (Exception e) {
            plugin.getLogger().log(Level.SEVERE, "Failed to hook into Vault economy", e);
            return false;
        }
    }

    /**
     * Gets the name of the active economy provider
     */
    public String getProviderName() {
        return vaultEconomy != null ? "Vault (" + vaultEconomy.getName() + ")" : "None";
    }

    /**
     * Gets a player's current balance
     *
     * @param playerUuid The player's UUID
     * @return The player's balance
     */
    public double getBalance(UUID playerUuid) {
        if (vaultEconomy == null) return 0.0;
        OfflinePlayer player = Bukkit.getOfflinePlayer(playerUuid);
        return vaultEconomy.getBalance(player);
    }

    /**
     * Checks if a player has at least the specified amount
     *
     * @param playerUuid The player's UUID
     * @param amount     The amount to check
     * @return true if the player has enough money
     */
    public boolean has(UUID playerUuid, double amount) {
        return getBalance(playerUuid) >= amount;
    }

    /**
     * Withdraws money from a player's account
     *
     * @param playerUuid The player's UUID
     * @param amount     The amount to withdraw
     * @return true if successful
     */
    public boolean withdraw(UUID playerUuid, double amount) {
        if (amount <= 0) return true;
        if (vaultEconomy == null) return false;

        OfflinePlayer player = Bukkit.getOfflinePlayer(playerUuid);
        if (!vaultEconomy.has(player, amount)) {
            return false;
        }
        return vaultEconomy.withdrawPlayer(player, amount).transactionSuccess();
    }

    /**
     * Deposits money into a player's account
     *
     * @param playerUuid The player's UUID
     * @param amount     The amount to deposit
     * @return true if successful
     */
    public boolean deposit(UUID playerUuid, double amount) {
        if (amount <= 0) return true;
        if (vaultEconomy == null) return false;

        OfflinePlayer player = Bukkit.getOfflinePlayer(playerUuid);
        return vaultEconomy.depositPlayer(player, amount).transactionSuccess();
    }

    /**
     * Transfers money between two players
     *
     * @param fromUuid The UUID of the payer
     * @param toUuid   The UUID of the receiver
     * @param amount   The amount to transfer
     * @return true if successful
     */
    public boolean transfer(UUID fromUuid, UUID toUuid, double amount) {
        if (amount <= 0) return true;

        // Withdraw first
        if (!withdraw(fromUuid, amount)) {
            return false;
        }

        // Then deposit - if this fails, refund the withdrawal
        if (!deposit(toUuid, amount)) {
            deposit(fromUuid, amount); // Attempt refund
            return false;
        }

        return true;
    }

    /**
     * Formats an amount according to the economy's formatting
     *
     * @param amount The amount to format
     * @return Formatted currency string
     */
    public String format(double amount) {
        if (vaultEconomy != null) {
            return vaultEconomy.format(amount);
        }
        return plugin.getMessageManager().formatCurrency(amount);
    }
}
