from datetime import datetime
from decimal import Decimal
from http import HTTPStatus

from fastapi import APIRouter, Depends, HTTPException
from lnbits.core.models import User, WalletTypeInfo
from lnbits.decorators import (
    check_super_user,
    check_user_exists,
    require_admin_key,
    require_invoice_key,
)
from lnbits.utils.exchange_rates import allowed_currencies, fiat_amount_as_satoshis

from .crud import (
    approve_manual_payment_request,
    check_balance_assertion,
    create_account,
    create_balance_assertion,
    create_journal_entry,
    create_manual_payment_request,
    db,
    delete_balance_assertion,
    get_account,
    get_account_balance,
    get_account_by_name,
    get_account_transactions,
    get_all_accounts,
    get_all_journal_entries,
    get_all_manual_payment_requests,
    get_all_user_balances,
    get_all_user_wallet_settings,
    get_balance_assertion,
    get_balance_assertions,
    get_journal_entries_by_user,
    get_journal_entry,
    get_manual_payment_request,
    get_or_create_user_account,
    get_user_balance,
    get_user_manual_payment_requests,
    reject_manual_payment_request,
)
from .models import (
    Account,
    AccountType,
    AssertionStatus,
    BalanceAssertion,
    CastleSettings,
    CreateAccount,
    CreateBalanceAssertion,
    CreateEntryLine,
    CreateJournalEntry,
    CreateManualPaymentRequest,
    ExpenseEntry,
    GeneratePaymentInvoice,
    JournalEntry,
    JournalEntryFlag,
    ManualPaymentRequest,
    PayUser,
    ReceivableEntry,
    RecordPayment,
    RevenueEntry,
    SettleReceivable,
    UserBalance,
    UserWalletSettings,
)
from .services import get_settings, get_user_wallet, update_settings, update_user_wallet

castle_api_router = APIRouter()


# ===== HELPER FUNCTIONS =====


async def check_castle_wallet_configured() -> str:
    """Ensure castle wallet is configured, return wallet_id"""
    settings = await get_settings("admin")
    if not settings or not settings.castle_wallet_id:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail="Castle wallet not configured. Please contact the super user to configure the Castle wallet in settings.",
        )
    return settings.castle_wallet_id


async def check_user_wallet_configured(user_id: str) -> str:
    """Ensure user has configured their wallet, return wallet_id"""
    from lnbits.settings import settings as lnbits_settings

    # If user is super user, use the castle wallet
    if user_id == lnbits_settings.super_user:
        castle_settings = await get_settings("admin")
        if castle_settings and castle_settings.castle_wallet_id:
            return castle_settings.castle_wallet_id
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail="Castle wallet not configured. Please configure the Castle wallet in settings.",
        )

    # For regular users, check their personal wallet
    user_wallet = await get_user_wallet(user_id)
    if not user_wallet or not user_wallet.user_wallet_id:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail="You must configure your wallet in settings before using this feature.",
        )
    return user_wallet.user_wallet_id


# ===== UTILITY ENDPOINTS =====


@castle_api_router.get("/api/v1/currencies")
async def api_get_currencies() -> list[str]:
    """Get list of allowed currencies for fiat conversion"""
    return allowed_currencies()


# ===== ACCOUNT ENDPOINTS =====


@castle_api_router.get("/api/v1/accounts")
async def api_get_accounts() -> list[Account]:
    """Get all accounts in the chart of accounts"""
    return await get_all_accounts()


@castle_api_router.post("/api/v1/accounts", status_code=HTTPStatus.CREATED)
async def api_create_account(
    data: CreateAccount,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> Account:
    """Create a new account (admin only)"""
    return await create_account(data)


@castle_api_router.get("/api/v1/accounts/{account_id}")
async def api_get_account(account_id: str) -> Account:
    """Get a specific account"""
    account = await get_account(account_id)
    if not account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND, detail="Account not found"
        )
    return account


@castle_api_router.get("/api/v1/accounts/{account_id}/balance")
async def api_get_account_balance(account_id: str) -> dict:
    """Get account balance"""
    balance = await get_account_balance(account_id)
    return {"account_id": account_id, "balance": balance}


@castle_api_router.get("/api/v1/accounts/{account_id}/transactions")
async def api_get_account_transactions(account_id: str, limit: int = 100) -> list[dict]:
    """Get all transactions for an account"""
    transactions = await get_account_transactions(account_id, limit)
    return [
        {
            "journal_entry": entry.dict(),
            "entry_line": line.dict(),
        }
        for entry, line in transactions
    ]


# ===== JOURNAL ENTRY ENDPOINTS =====


@castle_api_router.get("/api/v1/entries")
async def api_get_journal_entries(limit: int = 100) -> list[JournalEntry]:
    """Get all journal entries"""
    return await get_all_journal_entries(limit)


@castle_api_router.get("/api/v1/entries/user")
async def api_get_user_entries(
    wallet: WalletTypeInfo = Depends(require_invoice_key),
    limit: int = 100,
) -> list[JournalEntry]:
    """Get journal entries that affect the current user's accounts"""
    from lnbits.settings import settings as lnbits_settings

    # If super user, show all journal entries
    if wallet.wallet.user == lnbits_settings.super_user:
        return await get_all_journal_entries(limit)

    return await get_journal_entries_by_user(wallet.wallet.user, limit)


@castle_api_router.get("/api/v1/entries/pending")
async def api_get_pending_entries(
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> list[JournalEntry]:
    """Get all pending expense entries that need approval (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can access this endpoint",
        )

    # Get all journal entries and filter for pending flag
    all_entries = await get_all_journal_entries(limit=1000)
    pending_entries = [e for e in all_entries if e.flag == JournalEntryFlag.PENDING]
    return pending_entries


@castle_api_router.get("/api/v1/entries/{entry_id}")
async def api_get_journal_entry(entry_id: str) -> JournalEntry:
    """Get a specific journal entry"""
    entry = await get_journal_entry(entry_id)
    if not entry:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND, detail="Journal entry not found"
        )
    return entry


@castle_api_router.post("/api/v1/entries", status_code=HTTPStatus.CREATED)
async def api_create_journal_entry(
    data: CreateJournalEntry,
    wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> JournalEntry:
    """Create a new journal entry"""
    try:
        return await create_journal_entry(data, wallet.wallet.id)
    except ValueError as e:
        raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))


# ===== SIMPLIFIED ENTRY ENDPOINTS =====


@castle_api_router.post("/api/v1/entries/expense", status_code=HTTPStatus.CREATED)
async def api_create_expense_entry(
    data: ExpenseEntry,
    wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> JournalEntry:
    """
    Create an expense entry for a user.
    If is_equity=True, records as equity contribution.
    If is_equity=False, records as liability (castle owes user).

    If currency is provided, amount is converted from fiat to satoshis.
    """
    # Check that castle wallet is configured
    await check_castle_wallet_configured()

    # Check that user has configured their wallet
    await check_user_wallet_configured(wallet.wallet.user)
    # Handle currency conversion
    amount_sats = int(data.amount)
    metadata = {}

    if data.currency:
        # Validate currency
        if data.currency.upper() not in allowed_currencies():
            raise HTTPException(
                status_code=HTTPStatus.BAD_REQUEST,
                detail=f"Currency '{data.currency}' not allowed. Use one of: {', '.join(allowed_currencies())}",
            )

        # Convert fiat to satoshis
        amount_sats = await fiat_amount_as_satoshis(float(data.amount), data.currency)

        # Store currency metadata (store fiat_amount as string to preserve Decimal precision)
        metadata = {
            "fiat_currency": data.currency.upper(),
            "fiat_amount": str(data.amount.quantize(Decimal("0.001"))),  # Store as string with 3 decimal places
            "fiat_rate": float(amount_sats) / float(data.amount) if data.amount > 0 else 0,
            "btc_rate": float(data.amount) / float(amount_sats) * 100_000_000 if amount_sats > 0 else 0,
        }

    # Get or create expense account
    expense_account = await get_account_by_name(data.expense_account)
    if not expense_account:
        # Try to get it by ID
        expense_account = await get_account(data.expense_account)
    if not expense_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=f"Expense account '{data.expense_account}' not found",
        )

    # Get or create user-specific account
    if data.is_equity:
        # Equity contribution
        user_account = await get_or_create_user_account(
            wallet.wallet.user, AccountType.EQUITY, "Member Equity"
        )
    else:
        # Liability (castle owes user)
        user_account = await get_or_create_user_account(
            wallet.wallet.user, AccountType.LIABILITY, "Accounts Payable"
        )

    # Create journal entry
    # DR Expense, CR User Account (Liability or Equity)
    description_suffix = f" ({metadata['fiat_amount']} {metadata['fiat_currency']})" if metadata else ""

    # Add meta information for audit trail
    entry_meta = {
        "source": "api",
        "created_via": "expense_entry",
        "user_id": wallet.wallet.user,
        "is_equity": data.is_equity,
    }

    entry_data = CreateJournalEntry(
        description=data.description + description_suffix,
        reference=data.reference,
        entry_date=data.entry_date,
        flag=JournalEntryFlag.PENDING,  # Expenses require admin approval
        meta=entry_meta,
        lines=[
            CreateEntryLine(
                account_id=expense_account.id,
                debit=amount_sats,
                credit=0,
                description=f"Expense paid by user {wallet.wallet.user[:8]}",
                metadata=metadata,
            ),
            CreateEntryLine(
                account_id=user_account.id,
                debit=0,
                credit=amount_sats,
                description=f"{'Equity contribution' if data.is_equity else 'Amount owed to user'}",
                metadata=metadata,
            ),
        ],
    )

    return await create_journal_entry(entry_data, wallet.wallet.id)


@castle_api_router.post("/api/v1/entries/receivable", status_code=HTTPStatus.CREATED)
async def api_create_receivable_entry(
    data: ReceivableEntry,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> JournalEntry:
    """
    Create an accounts receivable entry (user owes castle).
    Admin only to prevent abuse.

    If currency is provided, amount is converted from fiat to satoshis.
    """
    # Handle currency conversion
    amount_sats = int(data.amount)
    metadata = {}

    if data.currency:
        # Validate currency
        if data.currency.upper() not in allowed_currencies():
            raise HTTPException(
                status_code=HTTPStatus.BAD_REQUEST,
                detail=f"Currency '{data.currency}' not allowed. Use one of: {', '.join(allowed_currencies())}",
            )

        # Convert fiat to satoshis
        amount_sats = await fiat_amount_as_satoshis(float(data.amount), data.currency)

        # Store currency metadata (store fiat_amount as string to preserve Decimal precision)
        metadata = {
            "fiat_currency": data.currency.upper(),
            "fiat_amount": str(data.amount.quantize(Decimal("0.001"))),  # Store as string with 3 decimal places
            "fiat_rate": float(amount_sats) / float(data.amount) if data.amount > 0 else 0,
            "btc_rate": float(data.amount) / float(amount_sats) * 100_000_000 if amount_sats > 0 else 0,
        }

    # Get or create revenue account
    revenue_account = await get_account_by_name(data.revenue_account)
    if not revenue_account:
        revenue_account = await get_account(data.revenue_account)
    if not revenue_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=f"Revenue account '{data.revenue_account}' not found",
        )

    # Get or create user-specific receivable account
    user_receivable = await get_or_create_user_account(
        data.user_id, AccountType.ASSET, "Accounts Receivable"
    )

    # Create journal entry
    # DR Accounts Receivable (User), CR Revenue
    description_suffix = f" ({metadata['fiat_amount']} {metadata['fiat_currency']})" if metadata else ""

    # Add meta information for audit trail
    entry_meta = {
        "source": "api",
        "created_via": "receivable_entry",
        "debtor_user_id": data.user_id,
    }

    entry_data = CreateJournalEntry(
        description=data.description + description_suffix,
        reference=data.reference,
        flag=JournalEntryFlag.PENDING,  # Receivables start as pending until paid
        meta=entry_meta,
        lines=[
            CreateEntryLine(
                account_id=user_receivable.id,
                debit=amount_sats,
                credit=0,
                description=f"Amount owed by user {data.user_id[:8]}",
                metadata=metadata,
            ),
            CreateEntryLine(
                account_id=revenue_account.id,
                debit=0,
                credit=amount_sats,
                description="Revenue earned",
                metadata=metadata,
            ),
        ],
    )

    return await create_journal_entry(entry_data, wallet.wallet.id)


@castle_api_router.post("/api/v1/entries/revenue", status_code=HTTPStatus.CREATED)
async def api_create_revenue_entry(
    data: RevenueEntry,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> JournalEntry:
    """
    Create a revenue entry (castle receives payment).
    Admin only.
    """
    # Get revenue account
    revenue_account = await get_account_by_name(data.revenue_account)
    if not revenue_account:
        revenue_account = await get_account(data.revenue_account)
    if not revenue_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=f"Revenue account '{data.revenue_account}' not found",
        )

    # Get payment method account
    payment_account = await get_account_by_name(data.payment_method_account)
    if not payment_account:
        payment_account = await get_account(data.payment_method_account)
    if not payment_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=f"Payment account '{data.payment_method_account}' not found",
        )

    # Create journal entry
    # DR Cash/Lightning/Bank, CR Revenue
    entry_data = CreateJournalEntry(
        description=data.description,
        reference=data.reference,
        lines=[
            CreateEntryLine(
                account_id=payment_account.id,
                debit=data.amount,
                credit=0,
                description="Payment received",
            ),
            CreateEntryLine(
                account_id=revenue_account.id,
                debit=0,
                credit=data.amount,
                description="Revenue earned",
            ),
        ],
    )

    return await create_journal_entry(entry_data, wallet.wallet.id)


# ===== USER BALANCE ENDPOINTS =====


@castle_api_router.get("/api/v1/balance")
async def api_get_my_balance(
    wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> UserBalance:
    """Get current user's balance with the Castle"""
    from lnbits.settings import settings as lnbits_settings

    # If super user, show total castle position
    if wallet.wallet.user == lnbits_settings.super_user:
        all_balances = await get_all_user_balances()

        # Calculate total:
        # Positive balances = Castle owes users (liabilities)
        # Negative balances = Users owe Castle (receivables)
        # Net: positive means castle owes, negative means castle is owed
        total_liabilities = sum(b.balance for b in all_balances if b.balance > 0)
        total_receivables = sum(abs(b.balance) for b in all_balances if b.balance < 0)
        net_balance = total_liabilities - total_receivables

        # Aggregate fiat balances from all users
        total_fiat_balances = {}
        for user_balance in all_balances:
            for currency, amount in user_balance.fiat_balances.items():
                if currency not in total_fiat_balances:
                    total_fiat_balances[currency] = Decimal("0")
                # Add all balances (positive and negative)
                total_fiat_balances[currency] += amount

        # Return net position
        return UserBalance(
            user_id=wallet.wallet.user,
            balance=net_balance,
            accounts=[],
            fiat_balances=total_fiat_balances,
        )

    # For regular users, show their individual balance
    return await get_user_balance(wallet.wallet.user)


@castle_api_router.get("/api/v1/balance/{user_id}")
async def api_get_user_balance(user_id: str) -> UserBalance:
    """Get a specific user's balance with the Castle"""
    return await get_user_balance(user_id)


@castle_api_router.get("/api/v1/balances/all")
async def api_get_all_balances(
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> list[dict]:
    """Get all user balances (admin/super user only)"""
    from lnbits.core.crud.users import get_user

    balances = await get_all_user_balances()

    # Enrich with username information
    result = []
    for balance in balances:
        user = await get_user(balance.user_id)
        username = user.username if user and user.username else balance.user_id[:16] + "..."

        result.append({
            "user_id": balance.user_id,
            "username": username,
            "balance": balance.balance,
            "fiat_balances": balance.fiat_balances,
            "accounts": [acc.dict() for acc in balance.accounts],
        })

    return result


# ===== PAYMENT ENDPOINTS =====


@castle_api_router.post("/api/v1/generate-payment-invoice")
async def api_generate_payment_invoice(
    data: GeneratePaymentInvoice,
    wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> dict:
    """
    Generate an invoice on the Castle wallet for user to pay their balance.
    User can then pay this invoice to settle their debt.

    If user_id is provided (admin only), the invoice is generated for that specific user.
    """
    from lnbits.core.crud.wallets import get_wallet
    from lnbits.core.models import CreateInvoice
    from lnbits.core.services import create_payment_request
    from lnbits.settings import settings as lnbits_settings

    # Determine which user this invoice is for
    if data.user_id:
        # Admin generating invoice for a specific user
        if wallet.wallet.user != lnbits_settings.super_user:
            raise HTTPException(
                status_code=HTTPStatus.FORBIDDEN,
                detail="Only super user can generate invoices for other users",
            )
        target_user_id = data.user_id
    else:
        # User generating invoice for themselves
        target_user_id = wallet.wallet.user

    # Get castle wallet ID
    castle_wallet_id = await check_castle_wallet_configured()

    # Create invoice on castle wallet
    invoice_data = CreateInvoice(
        out=False,
        amount=data.amount,
        memo=f"Payment from user {target_user_id[:8]} to Castle",
        unit="sat",
        extra={"user_id": target_user_id, "type": "castle_payment"},
    )

    payment = await create_payment_request(castle_wallet_id, invoice_data)

    # Get castle wallet to return its inkey for payment checking
    castle_wallet = await get_wallet(castle_wallet_id)
    if not castle_wallet:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND, detail="Castle wallet not found"
        )

    return {
        "payment_hash": payment.payment_hash,
        "payment_request": payment.bolt11,
        "amount": data.amount,
        "memo": invoice_data.memo,
        "check_wallet_key": castle_wallet.inkey,  # Key to check payment status
    }


@castle_api_router.post("/api/v1/record-payment")
async def api_record_payment(
    data: RecordPayment,
    wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> dict:
    """
    Record a lightning payment in accounting after invoice is paid.
    This reduces what the user owes to the castle.

    The user_id is extracted from the payment metadata (set during invoice generation).
    """
    from lnbits.core.crud.payments import get_standalone_payment

    # Get the payment details (incoming=True to get the invoice, not the payment)
    payment = await get_standalone_payment(data.payment_hash, incoming=True)
    if not payment:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND, detail="Payment not found"
        )

    if payment.pending:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST, detail="Payment not yet settled"
        )

    # Get user_id from payment metadata (set during invoice generation)
    target_user_id = None
    if payment.extra and isinstance(payment.extra, dict):
        target_user_id = payment.extra.get("user_id")

    if not target_user_id:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail="Payment metadata missing user_id. Cannot determine which user to credit.",
        )

    # Convert amount from millisatoshis to satoshis
    amount_sats = payment.amount // 1000

    # Get user's receivable account (what user owes)
    user_receivable = await get_or_create_user_account(
        target_user_id, AccountType.ASSET, "Accounts Receivable"
    )

    # Get lightning account
    lightning_account = await get_account_by_name("Assets:Bitcoin:Lightning")
    if not lightning_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND, detail="Lightning account not found"
        )

    # Create journal entry to record payment
    # DR Assets:Bitcoin:Lightning, CR Assets:Receivable (User)
    # This reduces what the user owes

    # Add meta information for audit trail
    entry_meta = {
        "source": "lightning_payment",
        "created_via": "record_payment",
        "payment_hash": data.payment_hash,
        "payer_user_id": target_user_id,
    }

    entry_data = CreateJournalEntry(
        description=f"Lightning payment from user {target_user_id[:8]}",
        reference=data.payment_hash,
        flag=JournalEntryFlag.CLEARED,  # Payment is immediately cleared
        meta=entry_meta,
        lines=[
            CreateEntryLine(
                account_id=lightning_account.id,
                debit=amount_sats,
                credit=0,
                description="Lightning payment received",
            ),
            CreateEntryLine(
                account_id=user_receivable.id,
                debit=0,
                credit=amount_sats,
                description="Payment applied to balance",
            ),
        ],
    )

    entry = await create_journal_entry(entry_data, target_user_id)

    # Get updated balance
    balance = await get_user_balance(target_user_id)

    return {
        "journal_entry_id": entry.id,
        "new_balance": balance.balance,
        "message": "Payment recorded successfully",
    }


@castle_api_router.post("/api/v1/pay-user")
async def api_pay_user(
    user_id: str,
    amount: int,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """
    Record a payment from castle to user (reduces what castle owes user).
    Admin only.
    """
    # Get user's payable account (what castle owes)
    user_payable = await get_or_create_user_account(
        user_id, AccountType.LIABILITY, "Accounts Payable"
    )

    # Get lightning account
    lightning_account = await get_account_by_name("Assets:Bitcoin:Lightning")
    if not lightning_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND, detail="Lightning account not found"
        )

    # Create journal entry
    # DR Liabilities:Payable (User), CR Assets:Bitcoin:Lightning
    entry_data = CreateJournalEntry(
        description=f"Payment to user {user_id[:8]}",
        lines=[
            CreateEntryLine(
                account_id=user_payable.id,
                debit=amount,
                credit=0,
                description="Payment made to user",
            ),
            CreateEntryLine(
                account_id=lightning_account.id,
                debit=0,
                credit=amount,
                description="Lightning payment sent",
            ),
        ],
    )

    entry = await create_journal_entry(entry_data, wallet.wallet.id)

    # Get updated balance
    balance = await get_user_balance(user_id)

    return {
        "journal_entry": entry.dict(),
        "new_balance": balance.balance,
        "message": "Payment recorded successfully",
    }


@castle_api_router.post("/api/v1/receivables/settle")
async def api_settle_receivable(
    data: SettleReceivable,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """
    Manually settle a receivable (record when user pays castle in person).

    This endpoint is for non-lightning payments like:
    - Cash payments
    - Bank transfers
    - Other manual settlements

    Admin only.
    """
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can settle receivables",
        )

    # Validate payment method
    valid_methods = ["cash", "bank_transfer", "check", "lightning", "btc_onchain", "other"]
    if data.payment_method.lower() not in valid_methods:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail=f"Invalid payment method. Must be one of: {', '.join(valid_methods)}",
        )

    # Get user's receivable account (what user owes)
    user_receivable = await get_or_create_user_account(
        data.user_id, AccountType.ASSET, "Accounts Receivable"
    )

    # Get the appropriate asset account based on payment method
    payment_account_map = {
        "cash": "Cash",
        "bank_transfer": "Bank Account",
        "check": "Bank Account",
        "lightning": "Assets:Bitcoin:Lightning",
        "btc_onchain": "Assets:Bitcoin:OnChain",
        "other": "Cash"
    }

    account_name = payment_account_map.get(data.payment_method.lower(), "Cash")
    payment_account = await get_account_by_name(account_name)

    # If account doesn't exist, try to find or create a generic one
    if not payment_account:
        # Try to find any asset account that's not receivable
        all_accounts = await get_all_accounts()
        for acc in all_accounts:
            if acc.account_type == AccountType.ASSET and "receivable" not in acc.name.lower():
                payment_account = acc
                break

    if not payment_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=f"Payment account '{account_name}' not found. Please create it first.",
        )

    # Create journal entry
    # DR Cash/Bank (asset increased), CR Accounts Receivable (asset decreased)
    # This records that user paid their debt

    # Determine the amount to record in the journal
    # IMPORTANT: Always record in satoshis to match the receivable account balance
    from decimal import Decimal

    if data.currency:
        # Fiat currency payment (e.g., EUR, USD)
        # Use the sats equivalent for the journal entry to match the receivable
        if not data.amount_sats:
            raise HTTPException(
                status_code=HTTPStatus.BAD_REQUEST,
                detail="amount_sats is required when settling with fiat currency"
            )
        amount_in_sats = data.amount_sats
        line_metadata = {
            "fiat_currency": data.currency.upper(),
            "fiat_amount": str(data.amount.quantize(Decimal("0.001"))),
            "fiat_rate": float(data.amount_sats) / float(data.amount) if data.amount > 0 else 0,
            "btc_rate": float(data.amount) / float(data.amount_sats) * 100_000_000 if data.amount_sats > 0 else 0,
        }
    else:
        # Satoshi payment
        amount_in_sats = int(data.amount)
        line_metadata = {}

    # Add payment hash for lightning payments
    if data.payment_hash:
        line_metadata["payment_hash"] = data.payment_hash

    # Add transaction ID for on-chain Bitcoin payments
    if data.txid:
        line_metadata["txid"] = data.txid

    # Add meta information for audit trail
    entry_meta = {
        "source": "manual_settlement",
        "payment_method": data.payment_method,
        "settled_by": wallet.wallet.user,
        "payer_user_id": data.user_id,
    }
    if data.currency:
        entry_meta["currency"] = data.currency

    entry_data = CreateJournalEntry(
        description=data.description,
        reference=data.reference or f"MANUAL-{data.user_id[:8]}",
        flag=JournalEntryFlag.CLEARED,  # Manual payments are immediately cleared
        meta=entry_meta,
        lines=[
            CreateEntryLine(
                account_id=payment_account.id,
                debit=amount_in_sats,
                credit=0,
                description=f"Payment received via {data.payment_method}",
                metadata=line_metadata,
            ),
            CreateEntryLine(
                account_id=user_receivable.id,
                debit=0,
                credit=amount_in_sats,
                description="Receivable settled",
                metadata=line_metadata,
            ),
        ],
    )

    entry = await create_journal_entry(entry_data, wallet.wallet.id)

    # Get updated balance
    balance = await get_user_balance(data.user_id)

    return {
        "journal_entry_id": entry.id,
        "user_id": data.user_id,
        "amount_settled": float(data.amount),
        "currency": data.currency,
        "payment_method": data.payment_method,
        "new_balance": balance.balance,
        "message": f"Receivable settled successfully via {data.payment_method}",
    }


@castle_api_router.post("/api/v1/payables/pay")
async def api_pay_user(
    data: PayUser,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """
    Pay a user (castle pays user for expense/liability).

    This endpoint is for both lightning and manual payments:
    - Lightning payments: already executed, just record the payment
    - Cash/Bank/Check: record manual payment that was made

    Admin only.
    """
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can pay users",
        )

    # Validate payment method
    valid_methods = ["cash", "bank_transfer", "check", "lightning", "btc_onchain", "other"]
    if data.payment_method.lower() not in valid_methods:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail=f"Invalid payment method. Must be one of: {', '.join(valid_methods)}",
        )

    # Get user's payable account (what castle owes)
    user_payable = await get_or_create_user_account(
        data.user_id, AccountType.LIABILITY, "Accounts Payable"
    )

    # Get the appropriate asset account based on payment method
    payment_account_map = {
        "cash": "Cash",
        "bank_transfer": "Bank Account",
        "check": "Bank Account",
        "lightning": "Assets:Bitcoin:Lightning",
        "btc_onchain": "Assets:Bitcoin:OnChain",
        "other": "Cash"
    }

    account_name = payment_account_map.get(data.payment_method.lower(), "Cash")
    payment_account = await get_account_by_name(account_name)

    if not payment_account:
        # Try to find any asset account that's not receivable
        all_accounts = await get_all_accounts()
        for acc in all_accounts:
            if acc.account_type == AccountType.ASSET and "receivable" not in acc.name.lower():
                payment_account = acc
                break

    if not payment_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=f"Payment account '{account_name}' not found. Please create it first.",
        )

    # Determine the amount to record in the journal
    # IMPORTANT: Always record in satoshis to match the payable account balance
    from decimal import Decimal

    if data.currency:
        # Fiat currency payment (e.g., EUR, USD)
        # Use the sats equivalent for the journal entry to match the payable
        if not data.amount_sats:
            raise HTTPException(
                status_code=HTTPStatus.BAD_REQUEST,
                detail="amount_sats is required when paying with fiat currency"
            )
        amount_in_sats = data.amount_sats
        line_metadata = {
            "fiat_currency": data.currency.upper(),
            "fiat_amount": str(data.amount.quantize(Decimal("0.001"))),
            "fiat_rate": float(data.amount_sats) / float(data.amount) if data.amount > 0 else 0,
            "btc_rate": float(data.amount) / float(data.amount_sats) * 100_000_000 if data.amount_sats > 0 else 0,
        }
    else:
        # Satoshi payment
        amount_in_sats = int(data.amount)
        line_metadata = {}

    # Add payment hash for lightning payments
    if data.payment_hash:
        line_metadata["payment_hash"] = data.payment_hash

    # Add transaction ID for on-chain Bitcoin payments
    if data.txid:
        line_metadata["txid"] = data.txid

    # Create journal entry
    # DR Accounts Payable (liability decreased), CR Cash/Lightning/Bank (asset decreased)
    # This records that castle paid its debt

    entry_meta = {
        "source": "manual_payment" if data.payment_method != "lightning" else "lightning_payment",
        "payment_method": data.payment_method,
        "paid_by": wallet.wallet.user,
        "payee_user_id": data.user_id,
    }
    if data.currency:
        entry_meta["currency"] = data.currency

    entry_data = CreateJournalEntry(
        description=data.description or f"Payment to user via {data.payment_method}",
        reference=data.reference or f"PAY-{data.user_id[:8]}",
        flag=JournalEntryFlag.CLEARED,  # Payments are immediately cleared
        meta=entry_meta,
        lines=[
            CreateEntryLine(
                account_id=user_payable.id,
                debit=amount_in_sats,
                credit=0,
                description="Payable settled",
                metadata=line_metadata,
            ),
            CreateEntryLine(
                account_id=payment_account.id,
                debit=0,
                credit=amount_in_sats,
                description=f"Payment sent via {data.payment_method}",
                metadata=line_metadata,
            ),
        ],
    )

    entry = await create_journal_entry(entry_data, wallet.wallet.id)

    # Get updated balance
    balance = await get_user_balance(data.user_id)

    return {
        "journal_entry_id": entry.id,
        "user_id": data.user_id,
        "amount_paid": float(data.amount),
        "currency": data.currency,
        "payment_method": data.payment_method,
        "new_balance": balance.balance,
        "message": f"User paid successfully via {data.payment_method}",
    }


# ===== SETTINGS ENDPOINTS =====


@castle_api_router.get("/api/v1/settings")
async def api_get_settings(
    user: User = Depends(check_user_exists),
) -> CastleSettings:
    """Get Castle settings"""
    user_id = "admin"
    settings = await get_settings(user_id)
    # Return empty settings if not configured (so UI can show setup screen)
    if not settings:
        return CastleSettings()
    return settings


@castle_api_router.put("/api/v1/settings")
async def api_update_settings(
    data: CastleSettings,
    user: User = Depends(check_super_user),
) -> CastleSettings:
    """Update Castle settings (super user only)"""
    if not data.castle_wallet_id:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail="Castle wallet ID is required",
        )
    user_id = "admin"
    return await update_settings(user_id, data)


# ===== USER WALLET ENDPOINTS =====


@castle_api_router.get("/api/v1/user-wallet/{user_id}")
async def api_get_user_wallet(
    user_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """Get user's wallet settings (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can access user wallet info",
        )

    user_wallet = await get_user_wallet(user_id)
    if not user_wallet:
        return {"user_id": user_id, "user_wallet_id": None}

    # Get invoice key for the user's wallet (needed to generate invoices)
    from lnbits.core.crud import get_wallet

    wallet_obj = await get_wallet(user_wallet.user_wallet_id)
    if not wallet_obj:
        return {"user_id": user_id, "user_wallet_id": user_wallet.user_wallet_id}

    return {
        "user_id": user_id,
        "user_wallet_id": user_wallet.user_wallet_id,
        "user_wallet_id_invoice_key": wallet_obj.inkey,
    }


@castle_api_router.get("/api/v1/users")
async def api_get_all_users(
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> list[dict]:
    """Get all users who have configured their wallet (admin only)"""
    from lnbits.core.crud.users import get_user

    user_settings = await get_all_user_wallet_settings()

    users = []
    for setting in user_settings:
        # Get user details from core
        user = await get_user(setting.id)

        # Use username if available, otherwise truncate user_id
        username = user.username if user and user.username else setting.id[:16] + "..."

        users.append({
            "user_id": setting.id,
            "user_wallet_id": setting.user_wallet_id,
            "username": username,
        })

    return users


@castle_api_router.get("/api/v1/user/wallet")
async def api_get_user_wallet(
    user: User = Depends(check_user_exists),
) -> UserWalletSettings:
    """Get current user's wallet settings"""
    from lnbits.settings import settings as lnbits_settings

    # If user is super user, return the castle wallet
    if user.id == lnbits_settings.super_user:
        castle_settings = await get_settings("admin")
        if castle_settings and castle_settings.castle_wallet_id:
            return UserWalletSettings(user_wallet_id=castle_settings.castle_wallet_id)
        return UserWalletSettings()

    # For regular users, get their personal wallet
    settings = await get_user_wallet(user.id)
    # Return empty settings if not configured (so UI can show setup screen)
    if not settings:
        return UserWalletSettings()
    return settings


@castle_api_router.put("/api/v1/user/wallet")
async def api_update_user_wallet(
    data: UserWalletSettings,
    user: User = Depends(check_user_exists),
) -> UserWalletSettings:
    """Update current user's wallet settings"""
    from lnbits.settings import settings as lnbits_settings

    # Super user cannot set their wallet separately - it's always the castle wallet
    if user.id == lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Super user wallet is automatically set to the Castle wallet. Update Castle settings instead.",
        )

    if not data.user_wallet_id:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail="User wallet ID is required",
        )
    return await update_user_wallet(user.id, data)


# ===== MANUAL PAYMENT REQUESTS =====


@castle_api_router.post("/api/v1/manual-payment-request")
async def api_create_manual_payment_request(
    data: CreateManualPaymentRequest,
    wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> ManualPaymentRequest:
    """Create a manual payment request for the Castle to review"""
    return await create_manual_payment_request(
        wallet.wallet.user, data.amount, data.description
    )


@castle_api_router.get("/api/v1/manual-payment-requests")
async def api_get_manual_payment_requests(
    wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> list[ManualPaymentRequest]:
    """Get manual payment requests for the current user"""
    return await get_user_manual_payment_requests(wallet.wallet.user)


@castle_api_router.get("/api/v1/manual-payment-requests/all")
async def api_get_all_manual_payment_requests(
    status: str = None,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> list[ManualPaymentRequest]:
    """Get all manual payment requests (Castle admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can access this endpoint",
        )
    return await get_all_manual_payment_requests(status)


@castle_api_router.post("/api/v1/manual-payment-requests/{request_id}/approve")
async def api_approve_manual_payment_request(
    request_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> ManualPaymentRequest:
    """Approve a manual payment request and create accounting entry (Castle admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can access this endpoint",
        )

    # Get the request
    request = await get_manual_payment_request(request_id)
    if not request:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Manual payment request not found",
        )

    if request.status != "pending":
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail=f"Request already {request.status}",
        )

    # Get castle wallet from settings
    castle_wallet_id = await check_castle_wallet_configured()

    # Get or create liability account for user (castle owes the user)
    liability_account = await get_or_create_user_account(
        request.user_id, AccountType.LIABILITY, "Accounts Payable"
    )

    # Get the Lightning asset account
    lightning_account = await get_account_by_name("Assets:Bitcoin:Lightning")
    if not lightning_account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Lightning account not found",
        )

    # Create journal entry: Debit Lightning (asset decreased), Credit Accounts Payable (liability increased)
    # This records that the Castle paid the user, reducing the lightning balance and reducing what castle owes
    journal_entry = await create_journal_entry(
        CreateJournalEntry(
            description=f"Manual payment to user: {request.description}",
            reference=f"MPR-{request.id}",
            lines=[
                CreateEntryLine(
                    account_id=liability_account.id,
                    debit=request.amount,  # Decrease liability (castle owes less)
                    credit=0,
                    description="Payment to user",
                ),
                CreateEntryLine(
                    account_id=lightning_account.id,
                    debit=0,
                    credit=request.amount,  # Decrease asset (lightning balance reduced)
                    description="Payment from castle",
                ),
            ],
        ),
        castle_wallet_id,
    )

    # Approve the request
    return await approve_manual_payment_request(
        request_id, wallet.wallet.user, journal_entry.id
    )


@castle_api_router.post("/api/v1/manual-payment-requests/{request_id}/reject")
async def api_reject_manual_payment_request(
    request_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> ManualPaymentRequest:
    """Reject a manual payment request (Castle admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can access this endpoint",
        )

    # Get the request
    request = await get_manual_payment_request(request_id)
    if not request:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Manual payment request not found",
        )

    if request.status != "pending":
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail=f"Request already {request.status}",
        )

    return await reject_manual_payment_request(request_id, wallet.wallet.user)


# ===== EXPENSE APPROVAL ENDPOINTS =====


@castle_api_router.post("/api/v1/entries/{entry_id}/approve")
async def api_approve_expense_entry(
    entry_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> JournalEntry:
    """Approve a pending expense entry (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can approve expenses",
        )

    # Get the entry
    entry = await get_journal_entry(entry_id)
    if not entry:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Journal entry not found",
        )

    if entry.flag != JournalEntryFlag.PENDING:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail=f"Entry is not pending (current status: {entry.flag.value})",
        )

    # Update flag to cleared
    await db.execute(
        """
        UPDATE journal_entries
        SET flag = :flag
        WHERE id = :id
        """,
        {"flag": JournalEntryFlag.CLEARED.value, "id": entry_id}
    )

    # Return updated entry
    return await get_journal_entry(entry_id)


@castle_api_router.post("/api/v1/entries/{entry_id}/reject")
async def api_reject_expense_entry(
    entry_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> JournalEntry:
    """Reject a pending expense entry (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can reject expenses",
        )

    # Get the entry
    entry = await get_journal_entry(entry_id)
    if not entry:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Journal entry not found",
        )

    if entry.flag != JournalEntryFlag.PENDING:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail=f"Entry is not pending (current status: {entry.flag.value})",
        )

    # Update flag to voided
    await db.execute(
        """
        UPDATE journal_entries
        SET flag = :flag
        WHERE id = :id
        """,
        {"flag": JournalEntryFlag.VOID.value, "id": entry_id}
    )

    # Return updated entry
    return await get_journal_entry(entry_id)


# ===== BALANCE ASSERTION ENDPOINTS =====


@castle_api_router.post("/api/v1/assertions")
async def api_create_balance_assertion(
    data: CreateBalanceAssertion,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> BalanceAssertion:
    """
    Create a balance assertion for reconciliation (admin only).
    The assertion will be checked immediately upon creation.
    """
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can create balance assertions",
        )

    # Verify account exists
    account = await get_account(data.account_id)
    if not account:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=f"Account {data.account_id} not found",
        )

    # Create the assertion
    assertion = await create_balance_assertion(data, wallet.wallet.user)

    # Check it immediately
    try:
        assertion = await check_balance_assertion(assertion.id)
    except ValueError as e:
        raise HTTPException(
            status_code=HTTPStatus.BAD_REQUEST,
            detail=str(e),
        )

    # If assertion failed, return 409 Conflict with details
    if assertion.status == AssertionStatus.FAILED:
        raise HTTPException(
            status_code=HTTPStatus.CONFLICT,
            detail={
                "message": "Balance assertion failed",
                "expected_sats": assertion.expected_balance_sats,
                "actual_sats": assertion.checked_balance_sats,
                "difference_sats": assertion.difference_sats,
                "expected_fiat": float(assertion.expected_balance_fiat) if assertion.expected_balance_fiat else None,
                "actual_fiat": float(assertion.checked_balance_fiat) if assertion.checked_balance_fiat else None,
                "difference_fiat": float(assertion.difference_fiat) if assertion.difference_fiat else None,
                "fiat_currency": assertion.fiat_currency,
            },
        )

    return assertion


@castle_api_router.get("/api/v1/assertions")
async def api_get_balance_assertions(
    account_id: str = None,
    status: str = None,
    limit: int = 100,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> list[BalanceAssertion]:
    """Get balance assertions with optional filters (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can view balance assertions",
        )

    # Parse status enum if provided
    status_enum = None
    if status:
        try:
            status_enum = AssertionStatus(status)
        except ValueError:
            raise HTTPException(
                status_code=HTTPStatus.BAD_REQUEST,
                detail=f"Invalid status: {status}. Must be one of: pending, passed, failed",
            )

    return await get_balance_assertions(
        account_id=account_id,
        status=status_enum,
        limit=limit,
    )


@castle_api_router.get("/api/v1/assertions/{assertion_id}")
async def api_get_balance_assertion(
    assertion_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> BalanceAssertion:
    """Get a specific balance assertion (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can view balance assertions",
        )

    assertion = await get_balance_assertion(assertion_id)
    if not assertion:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Balance assertion not found",
        )

    return assertion


@castle_api_router.post("/api/v1/assertions/{assertion_id}/check")
async def api_check_balance_assertion(
    assertion_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> BalanceAssertion:
    """Re-check a balance assertion (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can check balance assertions",
        )

    try:
        assertion = await check_balance_assertion(assertion_id)
    except ValueError as e:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail=str(e),
        )

    return assertion


@castle_api_router.delete("/api/v1/assertions/{assertion_id}")
async def api_delete_balance_assertion(
    assertion_id: str,
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """Delete a balance assertion (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can delete balance assertions",
        )

    # Verify it exists
    assertion = await get_balance_assertion(assertion_id)
    if not assertion:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Balance assertion not found",
        )

    await delete_balance_assertion(assertion_id)

    return {"success": True, "message": "Balance assertion deleted"}


# ===== RECONCILIATION ENDPOINTS =====


@castle_api_router.get("/api/v1/reconciliation/summary")
async def api_get_reconciliation_summary(
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """Get reconciliation summary (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can access reconciliation",
        )

    # Get all assertions
    all_assertions = await get_balance_assertions(limit=1000)

    # Count by status
    passed = len([a for a in all_assertions if a.status == AssertionStatus.PASSED])
    failed = len([a for a in all_assertions if a.status == AssertionStatus.FAILED])
    pending = len([a for a in all_assertions if a.status == AssertionStatus.PENDING])

    # Get all journal entries
    all_entries = await get_all_journal_entries(limit=1000)

    # Count entries by flag
    cleared = len([e for e in all_entries if e.flag == JournalEntryFlag.CLEARED])
    pending_entries = len([e for e in all_entries if e.flag == JournalEntryFlag.PENDING])
    flagged = len([e for e in all_entries if e.flag == JournalEntryFlag.FLAGGED])
    voided = len([e for e in all_entries if e.flag == JournalEntryFlag.VOID])

    # Get all accounts
    accounts = await get_all_accounts()

    return {
        "assertions": {
            "total": len(all_assertions),
            "passed": passed,
            "failed": failed,
            "pending": pending,
        },
        "entries": {
            "total": len(all_entries),
            "cleared": cleared,
            "pending": pending_entries,
            "flagged": flagged,
            "voided": voided,
        },
        "accounts": {
            "total": len(accounts),
        },
        "last_checked": datetime.now().isoformat(),
    }


@castle_api_router.post("/api/v1/reconciliation/check-all")
async def api_check_all_assertions(
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """Re-check all balance assertions (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can run reconciliation checks",
        )

    # Get all assertions
    all_assertions = await get_balance_assertions(limit=1000)

    results = {
        "total": len(all_assertions),
        "checked": 0,
        "passed": 0,
        "failed": 0,
        "errors": 0,
    }

    for assertion in all_assertions:
        try:
            checked = await check_balance_assertion(assertion.id)
            results["checked"] += 1
            if checked.status == AssertionStatus.PASSED:
                results["passed"] += 1
            elif checked.status == AssertionStatus.FAILED:
                results["failed"] += 1
        except Exception as e:
            results["errors"] += 1

    return results


@castle_api_router.get("/api/v1/reconciliation/discrepancies")
async def api_get_discrepancies(
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """Get all discrepancies (failed assertions, flagged entries) (admin only)"""
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can view discrepancies",
        )

    # Get failed assertions
    failed_assertions = await get_balance_assertions(
        status=AssertionStatus.FAILED,
        limit=1000,
    )

    # Get flagged entries
    all_entries = await get_all_journal_entries(limit=1000)
    flagged_entries = [e for e in all_entries if e.flag == JournalEntryFlag.FLAGGED]
    pending_entries = [e for e in all_entries if e.flag == JournalEntryFlag.PENDING]

    return {
        "failed_assertions": failed_assertions,
        "flagged_entries": flagged_entries,
        "pending_entries": pending_entries,
        "total_discrepancies": len(failed_assertions) + len(flagged_entries),
    }


# ===== AUTOMATED TASKS ENDPOINTS =====


@castle_api_router.post("/api/v1/tasks/daily-reconciliation")
async def api_run_daily_reconciliation(
    wallet: WalletTypeInfo = Depends(require_admin_key),
) -> dict:
    """
    Manually trigger the daily reconciliation check (admin only).
    This endpoint can also be called via cron job.

    Returns a summary of the reconciliation check results.
    """
    from lnbits.settings import settings as lnbits_settings

    if wallet.wallet.user != lnbits_settings.super_user:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="Only super user can run daily reconciliation",
        )

    from .tasks import check_all_balance_assertions

    try:
        results = await check_all_balance_assertions()
        return results
    except Exception as e:
        raise HTTPException(
            status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
            detail=f"Error running daily reconciliation: {str(e)}",
        )
