package com.bitnix.dirtcryptostore.manager;

import com.bitnix.dirtcryptostore.DirtCryptoStorePlugin;
import com.bitnix.dirtcryptostore.model.Product;
import com.bitnix.dirtcryptostore.util.HttpUtil;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

public class PricingManager {

    private final DirtCryptoStorePlugin plugin;

    private volatile double cachedBtcUsdPrice = -1.0D;
    private volatile long lastFetchTime = 0L;

    public PricingManager(DirtCryptoStorePlugin plugin) {
        this.plugin = plugin;
    }

    public long resolveBaseSats(Product product) {
        String mode = plugin.getConfig().getString("settings.pricing.mode", "BASE_SATS");

        if (!"LIVE_USD".equalsIgnoreCase(mode)) {
            return product.getBaseSats();
        }

        Double btcUsdPrice = getLiveBtcUsdPrice();
        if (btcUsdPrice == null || btcUsdPrice <= 0.0D) {
            boolean fallback = plugin.getConfig().getBoolean("settings.pricing.fallback-to-base-sats", true);
            return fallback ? product.getBaseSats() : -1L;
        }

        double usdPrice = product.getPriceUsd();
        if (usdPrice <= 0.0D) {
            return product.getBaseSats();
        }

        double btcAmount = usdPrice / btcUsdPrice;
        double sats = btcAmount * 100_000_000.0D;

        boolean roundUp = plugin.getConfig().getBoolean("settings.pricing.round-up-to-sat", true);
        long resolved = roundUp ? (long) Math.ceil(sats) : Math.round(sats);

        if (resolved <= 0L) {
            return -1L;
        }

        return resolved;
    }

    public Double getLiveBtcUsdPrice() {
        long cacheSeconds = plugin.getConfig().getLong("settings.pricing.cache-seconds", 60L);
        long now = System.currentTimeMillis();

        if (cachedBtcUsdPrice > 0.0D && (now - lastFetchTime) < (cacheSeconds * 1000L)) {
            return cachedBtcUsdPrice;
        }

        synchronized (this) {
            if (cachedBtcUsdPrice > 0.0D && (now - lastFetchTime) < (cacheSeconds * 1000L)) {
                return cachedBtcUsdPrice;
            }

            try {
                String provider = plugin.getConfig().getString("settings.pricing.live-rate-provider", "COINGECKO");
                if (!"COINGECKO".equalsIgnoreCase(provider)) {
                    return cachedBtcUsdPrice > 0.0D ? cachedBtcUsdPrice : null;
                }

                int timeout = plugin.getConfig().getInt("settings.blockchain.request-timeout-seconds", 10);
                String userAgent = plugin.getConfig().getString("settings.blockchain.user-agent", "DirtCryptoStore/1.0.0");
                String url = plugin.getConfig().getString(
                        "settings.pricing.coingecko-url",
                        "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd"
                );

                String json = HttpUtil.get(url, timeout, userAgent);
                JsonObject root = JsonParser.parseString(json).getAsJsonObject();
                JsonObject bitcoin = root.getAsJsonObject("bitcoin");
                if (bitcoin == null || !bitcoin.has("usd")) {
                    return cachedBtcUsdPrice > 0.0D ? cachedBtcUsdPrice : null;
                }

                double price = bitcoin.get("usd").getAsDouble();
                if (price > 0.0D) {
                    cachedBtcUsdPrice = price;
                    lastFetchTime = now;

                    if (plugin.getConfig().getBoolean("settings.debug", false)) {
                        plugin.getLogger().info("Updated live BTC/USD price: " + price);
                    }

                    return price;
                }
            } catch (Exception ex) {
                if (plugin.getConfig().getBoolean("settings.debug", false)) {
                    plugin.getLogger().warning("Failed to fetch live BTC price: " + ex.getMessage());
                }
            }

            return cachedBtcUsdPrice > 0.0D ? cachedBtcUsdPrice : null;
        }
    }

    public void clearCache() {
        cachedBtcUsdPrice = -1.0D;
        lastFetchTime = 0L;
    }
}
