import asyncio
import json

from lnbits.core import db as core_db
from lnbits.core.crud import create_payment
from lnbits.core.models import Payment
from lnbits.helpers import urlsafe_short_hash
from lnbits.tasks import internal_invoice_queue, register_invoice_listener

from .crud import get_tpos


async def wait_for_paid_invoices():
    invoice_queue = asyncio.Queue()
    register_invoice_listener(invoice_queue)

    while True:
        payment = await invoice_queue.get()
        await on_invoice_paid(payment)


async def on_invoice_paid(payment: Payment) -> None:
    if payment.extra.get("tag") == "tpos" and payment.extra.get("tipSplitted"):
        # already splitted, ignore
        return

    # now we make some special internal transfers (from no one to the receiver)
    tpos = await get_tpos(payment.extra.get("tposId"))
    tipAmount = payment.extra.get("tipAmount")

    if tipAmount is None:
        # no tip amount
        return

    tipAmount = tipAmount * 1000
    amount = payment.amount - tipAmount

    # mark the original payment with one extra key, "splitted"
    # (this prevents us from doing this process again and it's informative)
    # and reduce it by the amount we're going to send to the producer
    await core_db.execute(
        """
        UPDATE apipayments
        SET extra = ?, amount = ?
        WHERE hash = ?
          AND checking_id NOT LIKE 'internal_%'
        """,
        (
            json.dumps(dict(**payment.extra, tipSplitted=True)),
            amount,
            payment.payment_hash,
        ),
    )

    # perform the internal transfer using the same payment_hash
    internal_checking_id = f"internal_{urlsafe_short_hash()}"
    await create_payment(
        wallet_id=tpos.tip_wallet,
        checking_id=internal_checking_id,
        payment_request="",
        payment_hash=payment.payment_hash,
        amount=tipAmount,
        memo=f"Tip for {payment.memo}",
        pending=False,
        extra={"tipSplitted": True},
    )

    # manually send this for now
    await internal_invoice_queue.put(internal_checking_id)
    return
