"""
Wallet provider for creating and verifying Lightning invoices.

Supports custom wallet backends and includes a MockWallet for testing.
"""

from __future__ import annotations

import hashlib
import os
from typing import Callable, Awaitable, Optional, Protocol


class WalletBackend(Protocol):
    """Protocol for wallet implementations."""

    async def create_invoice(self, sats: int, description: str) -> dict:
        """Return {"invoice": str, "payment_hash": str}."""
        ...

    async def lookup_invoice(self, payment_hash: str) -> dict:
        """Return {"paid": bool, "preimage": str | None}."""
        ...


class WalletProvider:
    """Wallet wrapper that tracks invoices."""

    def __init__(self, backend: WalletBackend):
        self._backend = backend
        self._invoices: dict[str, dict] = {}

    async def create_invoice(self, sats: int, description: str) -> dict:
        result = await self._backend.create_invoice(sats, description)
        payment_hash = result["payment_hash"]
        self._invoices[payment_hash] = {
            "invoice": result["invoice"],
            "amount": sats,
            "paid": False,
        }
        return result

    async def lookup_invoice(self, payment_hash: str) -> dict:
        result = await self._backend.lookup_invoice(payment_hash)
        if result.get("paid") and payment_hash in self._invoices:
            self._invoices[payment_hash]["paid"] = True
        return result

    @staticmethod
    def verify_preimage(preimage: str, payment_hash: str) -> bool:
        computed = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
        return computed == payment_hash

    def stats(self) -> dict:
        paid = sum(1 for v in self._invoices.values() if v["paid"])
        total_sats = sum(v["amount"] for v in self._invoices.values() if v["paid"])
        return {
            "paid": paid,
            "pending": len(self._invoices) - paid,
            "total_sats": total_sats,
            "total": len(self._invoices),
        }


class MockWallet:
    """Mock wallet for testing — no real Lightning needed."""

    def __init__(self):
        self._invoices: dict[str, dict] = {}

    async def create_invoice(self, sats: int, description: str) -> dict:
        preimage = os.urandom(32).hex()
        payment_hash = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
        self._invoices[payment_hash] = {
            "preimage": preimage,
            "sats": sats,
            "paid": False,
        }
        return {
            "invoice": f"lnbc{sats}0n1mock_{payment_hash[:16]}",
            "payment_hash": payment_hash,
        }

    async def lookup_invoice(self, payment_hash: str) -> dict:
        inv = self._invoices.get(payment_hash)
        if not inv:
            return {"paid": False, "preimage": None}
        return {"paid": inv["paid"], "preimage": inv["preimage"] if inv["paid"] else None}

    def mock_pay(self, payment_hash: str) -> Optional[str]:
        """Simulate payment. Returns preimage."""
        inv = self._invoices.get(payment_hash)
        if inv:
            inv["paid"] = True
            return inv["preimage"]
        return None

    def get_preimage(self, payment_hash: str) -> Optional[str]:
        inv = self._invoices.get(payment_hash)
        return inv["preimage"] if inv else None
