import base64
import json

import requests

from nostr_dvm.utils.database_utils import get_or_add_user
from nostr_dvm.utils.zap_utils import create_bolt11_ln_bits, create_bolt11_lud16

BASE_URL = "https://mint.minibits.cash/Bitcoin"


def parse_cashu(cashu_token: str):
    try:
        prefix = "cashuA"
        assert cashu_token.startswith(prefix), Exception(
            f"Token prefix not valid. Expected {prefix}."
        )
        if not cashu_token.endswith("="):
            cashu_token = str(cashu_token) + "=="
        print(cashu_token)
        token_base64 = cashu_token[len(prefix):].encode("utf-8")
        cashu = json.loads(base64.urlsafe_b64decode(token_base64))
        token = cashu["token"][0]
        proofs = token["proofs"]
        mint = token["mint"]
        total_amount = 0
        for proof in proofs:
            total_amount += proof["amount"]

        return proofs, mint, total_amount, None

    except Exception as e:
        print(e)
        return None, None, None, "Cashu Parser: " + str(e)


async def redeem_cashu(cashu, config, client, required_amount=0, update_self=False) -> (bool, str, int, int):
    proofs, mint, total_amount, message = parse_cashu(cashu)
    if message is not None:
        return False, message, 0, 0

    estimated_fees = max(int(total_amount * 0.02), 3)
    estimated_redeem_invoice_amount = total_amount - estimated_fees

    # Not sure if this the best way to go, we first create an invoice that we send to the mint, we catch the fees
    # for that invoice, and create another invoice with the amount without fees to melt.
    if config.LNBITS_INVOICE_KEY != "":
        invoice, paymenthash = create_bolt11_ln_bits(estimated_redeem_invoice_amount, config)
    else:

        user = await get_or_add_user(db=config.DB, npub=config.PUBLIC_KEY,
                                     client=client, config=config, update=update_self)
        invoice = create_bolt11_lud16(user.lud16, estimated_redeem_invoice_amount)
    print(invoice)
    if invoice is None:
        return False, "couldn't create invoice", 0, 0

    url = mint + "/checkfees"  # Melt cashu tokens at Mint
    json_object = {"pr": invoice}
    headers = {"Content-Type": "application/json; charset=utf-8"}
    request_body = json.dumps(json_object).encode('utf-8')
    request = requests.post(url, data=request_body, headers=headers)
    tree = json.loads(request.text)
    fees = tree["fee"]
    print("Fees on this mint are " + str(fees) + " Sats")
    redeem_invoice_amount = total_amount - fees
    if redeem_invoice_amount < required_amount:
        err = ("Token value (Payment: " + str(total_amount) + " Sats. Fees: " +
               str(fees) + " Sats) below required amount of  " + str(required_amount)
               + " Sats. Cashu token has not been claimed.")
        print("[" + config.NIP89.NAME + "] " + err)
        return False, err, 0, 0

    if config.LNBITS_INVOICE_KEY != "":
        invoice, paymenthash = create_bolt11_ln_bits(redeem_invoice_amount, config)
    else:

        user = await get_or_add_user(db=config.DB, npub=config.PUBLIC_KEY,
                                     client=client, config=config, update=update_self)
        invoice = create_bolt11_lud16(user.lud16, redeem_invoice_amount)
    print(invoice)

    try:
        url = mint + "/melt"  # Melt cashu tokens at Mint
        json_object = {"proofs": proofs, "pr": invoice}
        headers = {"Content-Type": "application/json; charset=utf-8"}
        request_body = json.dumps(json_object).encode('utf-8')
        request = requests.post(url, data=request_body, headers=headers)
        tree = json.loads(request.text)
        print(request.text)
        is_paid = tree["paid"] if tree.get("paid") else False
        print(is_paid)
        if is_paid:
            print("cashu token redeemed")
            return True, "success", redeem_invoice_amount, fees
        else:
            msg = tree.get("detail").split('.')[0].strip() if tree.get("detail") else None
            print(msg)
            return False, msg, redeem_invoice_amount, fees
    except Exception as e:
        print(e)

    return False, "", redeem_invoice_amount, fees
