package com.bitnix.dirtcryptostore.manager;

import com.bitnix.dirtcryptostore.DirtCryptoStorePlugin;
import com.bitnix.dirtcryptostore.model.BlockchainPaymentMatch;
import com.bitnix.dirtcryptostore.model.PendingInvoice;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

public class BlockchainApi {

    private final DirtCryptoStorePlugin plugin;

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

    public BlockchainPaymentMatch findPayment(PendingInvoice invoice) {
        try {
            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 latestBlockJson = com.bitnix.dirtcryptostore.util.HttpUtil.get(
                    "https://blockchain.info/latestblock",
                    timeout,
                    userAgent
            );

            JsonObject latestBlockObject = JsonParser.parseString(latestBlockJson).getAsJsonObject();
            int latestHeight = latestBlockObject.has("height") ? latestBlockObject.get("height").getAsInt() : 0;

            String address = invoice.getWalletAddress();
            String rawAddrJson = com.bitnix.dirtcryptostore.util.HttpUtil.get(
                    "https://blockchain.info/rawaddr/" + address,
                    timeout,
                    userAgent
            );

            JsonObject root = JsonParser.parseString(rawAddrJson).getAsJsonObject();
            if (!root.has("txs") || !root.get("txs").isJsonArray()) {
                return new BlockchainPaymentMatch(false, "", 0, 0);
            }

            JsonArray txs = root.getAsJsonArray("txs");

            for (JsonElement txElement : txs) {
                if (!txElement.isJsonObject()) {
                    continue;
                }

                JsonObject tx = txElement.getAsJsonObject();
                String txid = tx.has("hash") ? tx.get("hash").getAsString() : "";
                int blockHeight = tx.has("block_height") ? tx.get("block_height").getAsInt() : 0;

                if (!tx.has("out") || !tx.get("out").isJsonArray()) {
                    continue;
                }

                JsonArray outs = tx.getAsJsonArray("out");
                for (JsonElement outElement : outs) {
                    if (!outElement.isJsonObject()) {
                        continue;
                    }

                    JsonObject out = outElement.getAsJsonObject();

                    if (!out.has("value")) {
                        continue;
                    }

                    long value = out.get("value").getAsLong();

                    String outAddress = "";
                    if (out.has("addr") && !out.get("addr").isJsonNull()) {
                        outAddress = out.get("addr").getAsString();
                    }

                    if (!outAddress.equalsIgnoreCase(address)) {
                        continue;
                    }

                    if (value != invoice.getAmountSats()) {
                        continue;
                    }

                    int confirmations = 0;
                    if (blockHeight > 0 && latestHeight > 0) {
                        confirmations = Math.max(1, (latestHeight - blockHeight) + 1);
                    }

                    if (plugin.getConfig().getBoolean("settings.debug", false)) {
                        plugin.getLogger().info("Matched invoice " + invoice.getInvoiceId()
                                + " to txid=" + txid
                                + " confirmations=" + confirmations
                                + " blockHeight=" + blockHeight);
                    }

                    return new BlockchainPaymentMatch(true, txid, confirmations, blockHeight);
                }
            }
        } catch (Exception ex) {
            if (plugin.getConfig().getBoolean("settings.debug", false)) {
                plugin.getLogger().warning("Blockchain lookup failed for invoice " + invoice.getInvoiceId() + ": " + ex.getMessage());
            }
        }

        return new BlockchainPaymentMatch(false, "", 0, 0);
    }
}
