const mapJournalEntry = obj => {
  return obj
}

window.app = Vue.createApp({
  el: '#vue',
  mixins: [windowMixin],
  data() {
    return {
      balance: null,
      allUserBalances: [],
      transactions: [],
      accounts: [],
      currencies: [],
      users: [],
      settings: null,
      userWalletSettings: null,
      isAdmin: false,
      isSuperUser: false,
      castleWalletConfigured: false,
      userWalletConfigured: false,
      currentExchangeRate: null, // BTC/EUR rate (sats per EUR)
      expenseDialog: {
        show: false,
        description: '',
        amount: null,
        expenseAccount: '',
        isEquity: false,
        reference: '',
        currency: 'EUR',
        date: new Date().toISOString().split('T')[0], // YYYY-MM-DD format
        loading: false
      },
      payDialog: {
        show: false,
        amount: null,
        paymentRequest: null,
        paymentHash: null,
        checkWalletKey: null,
        pollIntervalId: null,
        loading: false
      },
      settingsDialog: {
        show: false,
        castleWalletId: '',
        loading: false
      },
      userWalletDialog: {
        show: false,
        userWalletId: '',
        loading: false
      },
      receivableDialog: {
        show: false,
        selectedUser: '',
        description: '',
        amount: null,
        revenueAccount: '',
        reference: '',
        currency: null,
        loading: false
      },
      manualPaymentDialog: {
        show: false,
        amount: null,
        description: '',
        loading: false
      },
      manualPaymentRequests: [],
      pendingExpenses: [],
      balanceAssertions: [],
      assertionDialog: {
        show: false,
        account_id: '',
        expected_balance_sats: 0,
        expected_balance_fiat: null,
        fiat_currency: null,
        tolerance_sats: 0,
        tolerance_fiat: 0,
        loading: false
      },
      reconciliation: {
        summary: null,
        discrepancies: null,
        checking: false,
        showDiscrepancies: false
      },
      settleReceivableDialog: {
        show: false,
        user_id: '',
        username: '',
        maxAmount: 0,
        amount: 0,
        payment_method: 'cash',
        description: '',
        reference: '',
        loading: false,
        invoice: null,
        paymentHash: null,
        checkWalletKey: null,
        pollIntervalId: null,
        exchangeRate: null, // Will be set from currentExchangeRate
        originalCurrency: 'BTC' // Track original receivable currency
      },
      payUserDialog: {
        show: false,
        user_id: '',
        username: '',
        maxAmount: 0,
        maxAmountFiat: 0,
        fiatCurrency: null,
        amount: 0,
        payment_method: 'lightning',
        description: '',
        reference: '',
        loading: false,
        paymentSuccess: false,
        exchangeRate: null, // Will be set from currentExchangeRate
        originalCurrency: 'BTC'
      }
    }
  },
  watch: {
    'payDialog.show': function(newVal) {
      // When dialog is closed, stop polling
      if (!newVal && this.payDialog.pollIntervalId) {
        clearInterval(this.payDialog.pollIntervalId)
        this.payDialog.pollIntervalId = null
      }
    },
    'settleReceivableDialog.show': function(newVal) {
      // When dialog is closed, stop polling
      if (!newVal && this.settleReceivableDialog.pollIntervalId) {
        clearInterval(this.settleReceivableDialog.pollIntervalId)
        this.settleReceivableDialog.pollIntervalId = null
      }
    },
    'settleReceivableDialog.payment_method': function(newVal, oldVal) {
      // Convert amount when payment method changes between cash and lightning
      if (!oldVal) return

      const isOldCash = ['cash', 'bank_transfer', 'check'].includes(oldVal)
      const isNewCash = ['cash', 'bank_transfer', 'check'].includes(newVal)

      // Only convert if switching between cash and lightning
      if (isOldCash === isNewCash) return

      // Convert from fiat to sats (when switching from cash to lightning)
      if (isOldCash && !isNewCash) {
        this.settleReceivableDialog.amount = this.settleReceivableDialog.maxAmount
      }
      // Convert from sats to fiat (when switching from lightning to cash)
      else if (!isOldCash && isNewCash) {
        this.settleReceivableDialog.amount = this.settleReceivableDialog.maxAmountFiat || 0
      }
    },
    'payUserDialog.payment_method': function(newVal, oldVal) {
      // Convert amount when payment method changes between cash and lightning
      if (!oldVal) return

      const isOldCash = ['cash', 'bank_transfer', 'check'].includes(oldVal)
      const isNewCash = ['cash', 'bank_transfer', 'check'].includes(newVal)

      // Only convert if switching between cash and lightning
      if (isOldCash === isNewCash) return

      // Convert from fiat to sats (when switching from cash to lightning)
      if (isOldCash && !isNewCash) {
        this.payUserDialog.amount = this.payUserDialog.maxAmount
      }
      // Convert from sats to fiat (when switching from lightning to cash)
      else if (!isOldCash && isNewCash) {
        this.payUserDialog.amount = this.payUserDialog.maxAmountFiat || 0
      }
    }
  },
  computed: {
    expenseAccounts() {
      return this.accounts.filter(a => a.account_type === 'expense')
    },
    revenueAccounts() {
      return this.accounts.filter(a => a.account_type === 'revenue')
    },
    amountLabel() {
      if (this.expenseDialog.currency) {
        return `Amount (${this.expenseDialog.currency}) *`
      }
      return 'Amount (sats) *'
    },
    receivableAmountLabel() {
      if (this.receivableDialog.currency) {
        return `Amount (${this.receivableDialog.currency}) *`
      }
      return 'Amount (sats) *'
    },
    settlementAmountLabel() {
      const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
        this.settleReceivableDialog.payment_method
      )
      if (isCashPayment && this.settleReceivableDialog.fiatCurrency) {
        return `Settlement Amount (${this.settleReceivableDialog.fiatCurrency}) *`
      }
      return 'Settlement Amount (sats) *'
    },
    settlementMaxAmount() {
      const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
        this.settleReceivableDialog.payment_method
      )
      if (isCashPayment && this.settleReceivableDialog.maxAmountFiat) {
        return this.settleReceivableDialog.maxAmountFiat
      }
      return this.settleReceivableDialog.maxAmount
    },
    settlementAmountStep() {
      const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
        this.settleReceivableDialog.payment_method
      )
      return isCashPayment ? '0.01' : '1'
    },
    paymentAmountLabel() {
      const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
        this.payUserDialog.payment_method
      )
      if (isCashPayment && this.payUserDialog.fiatCurrency) {
        return `Payment Amount (${this.payUserDialog.fiatCurrency}) *`
      }
      return 'Payment Amount (sats) *'
    },
    paymentMaxAmount() {
      const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
        this.payUserDialog.payment_method
      )
      if (isCashPayment && this.payUserDialog.maxAmountFiat) {
        return this.payUserDialog.maxAmountFiat
      }
      return this.payUserDialog.maxAmount
    },
    paymentAmountStep() {
      const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
        this.payUserDialog.payment_method
      )
      return isCashPayment ? '0.01' : '1'
    },
    currencyOptions() {
      const options = [{label: 'Satoshis (default)', value: null}]
      this.currencies.forEach(curr => {
        options.push({label: curr, value: curr})
      })
      return options
    },
    userOptions() {
      const options = []
      this.users.forEach(user => {
        options.push({
          label: user.username,
          value: user.user_id
        })
      })
      return options
    },
    pendingManualPaymentRequests() {
      return this.manualPaymentRequests.filter(r => r.status === 'pending')
    },
    failedAssertions() {
      return this.balanceAssertions.filter(a => a.status === 'failed')
    },
    outstandingUserBalances() {
      // Filter to only show users with non-zero balances
      return this.allUserBalances.filter(user => user.balance !== 0)
    },
    passedAssertions() {
      return this.balanceAssertions.filter(a => a.status === 'passed')
    },
    allAccounts() {
      return this.accounts
    }
  },
  methods: {
    async loadBalance() {
      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/balance',
          this.g.user.wallets[0].inkey
        )
        this.balance = response.data

        // If super user, also load all user balances
        if (this.isSuperUser) {
          await this.loadAllUserBalances()
        }
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async loadAllUserBalances() {
      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/balances/all',
          this.g.user.wallets[0].adminkey
        )
        this.allUserBalances = response.data
      } catch (error) {
        console.error('Error loading all user balances:', error)
      }
    },
    async loadTransactions() {
      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/entries/user',
          this.g.user.wallets[0].inkey
        )
        this.transactions = response.data
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async loadAccounts() {
      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/accounts',
          this.g.user.wallets[0].inkey
        )
        this.accounts = response.data
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async loadCurrencies() {
      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/currencies',
          this.g.user.wallets[0].inkey
        )
        this.currencies = response.data
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async loadUsers() {
      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/users',
          this.g.user.wallets[0].adminkey
        )
        this.users = response.data
      } catch (error) {
        console.error('Error loading users:', error)
      }
    },
    async loadSettings() {
      try {
        // Try with admin key first to check settings
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/settings',
          this.g.user.wallets[0].inkey
        )
        this.settings = response.data
        this.castleWalletConfigured = !!(this.settings && this.settings.castle_wallet_id)

        // Check if user is super user by seeing if they can access admin features
        this.isSuperUser = this.g.user.super_user || false
        this.isAdmin = this.g.user.admin || this.isSuperUser
      } catch (error) {
        // Settings not available
        this.castleWalletConfigured = false
      }
    },
    async loadUserWallet() {
      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/user/wallet',
          this.g.user.wallets[0].inkey
        )
        this.userWalletSettings = response.data
        this.userWalletConfigured = !!(this.userWalletSettings && this.userWalletSettings.user_wallet_id)
      } catch (error) {
        this.userWalletConfigured = false
      }
    },
    showSettingsDialog() {
      this.settingsDialog.castleWalletId = this.settings?.castle_wallet_id || ''
      this.settingsDialog.show = true
    },
    showUserWalletDialog() {
      this.userWalletDialog.userWalletId = this.userWalletSettings?.user_wallet_id || ''
      this.userWalletDialog.show = true
    },
    async submitSettings() {
      if (!this.settingsDialog.castleWalletId) {
        this.$q.notify({
          type: 'warning',
          message: 'Castle Wallet ID is required'
        })
        return
      }

      this.settingsDialog.loading = true
      try {
        await LNbits.api.request(
          'PUT',
          '/castle/api/v1/settings',
          this.g.user.wallets[0].adminkey,
          {
            castle_wallet_id: this.settingsDialog.castleWalletId
          }
        )
        this.$q.notify({
          type: 'positive',
          message: 'Settings updated successfully'
        })
        this.settingsDialog.show = false
        await this.loadSettings()
        // Reload user wallet to reflect castle wallet for super user
        if (this.isSuperUser) {
          await this.loadUserWallet()
        }
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.settingsDialog.loading = false
      }
    },
    async submitUserWallet() {
      if (!this.userWalletDialog.userWalletId) {
        this.$q.notify({
          type: 'warning',
          message: 'Wallet ID is required'
        })
        return
      }

      this.userWalletDialog.loading = true
      try {
        await LNbits.api.request(
          'PUT',
          '/castle/api/v1/user/wallet',
          this.g.user.wallets[0].inkey,
          {
            user_wallet_id: this.userWalletDialog.userWalletId
          }
        )
        this.$q.notify({
          type: 'positive',
          message: 'Wallet configured successfully'
        })
        this.userWalletDialog.show = false
        await this.loadUserWallet()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.userWalletDialog.loading = false
      }
    },
    async submitExpense() {
      this.expenseDialog.loading = true
      try {
        await LNbits.api.request(
          'POST',
          '/castle/api/v1/entries/expense',
          this.g.user.wallets[0].inkey,
          {
            description: this.expenseDialog.description,
            amount: this.expenseDialog.amount,
            expense_account: this.expenseDialog.expenseAccount,
            is_equity: this.expenseDialog.isEquity,
            user_wallet: this.g.user.wallets[0].id,
            reference: this.expenseDialog.reference || null,
            currency: this.expenseDialog.currency || null,
            entry_date: this.expenseDialog.date ? `${this.expenseDialog.date}T00:00:00` : null
          }
        )
        this.$q.notify({
          type: 'positive',
          message: 'Expense added successfully'
        })
        this.expenseDialog.show = false
        this.resetExpenseDialog()
        await this.loadBalance()
        await this.loadTransactions()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.expenseDialog.loading = false
      }
    },
    async submitPayment() {
      this.payDialog.loading = true

      // Clear any existing polling interval
      if (this.payDialog.pollIntervalId) {
        clearInterval(this.payDialog.pollIntervalId)
        this.payDialog.pollIntervalId = null
      }

      try {
        // Generate an invoice on the Castle wallet
        const response = await LNbits.api.request(
          'POST',
          '/castle/api/v1/generate-payment-invoice',
          this.g.user.wallets[0].inkey,
          {
            amount: this.payDialog.amount
          }
        )

        // Show the payment request in the dialog
        this.payDialog.paymentRequest = response.data.payment_request
        this.payDialog.paymentHash = response.data.payment_hash
        this.payDialog.checkWalletKey = response.data.check_wallet_key

        this.$q.notify({
          type: 'positive',
          message: 'Invoice generated! Scan QR code or copy to pay.',
          timeout: 3000
        })

        // Poll for payment completion
        this.pollForPayment(response.data.payment_hash, response.data.check_wallet_key)
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.payDialog.loading = false
      }
    },
    async pollForPayment(paymentHash, checkWalletKey) {
      // Clear any existing interval
      if (this.payDialog.pollIntervalId) {
        clearInterval(this.payDialog.pollIntervalId)
      }

      // Poll every 2 seconds for payment status
      const checkPayment = async () => {
        try {
          const response = await LNbits.api.request(
            'GET',
            `/api/v1/payments/${paymentHash}`,
            checkWalletKey
          )

          if (response.data && response.data.paid) {
            // Record payment in accounting
            try {
              await LNbits.api.request(
                'POST',
                '/castle/api/v1/record-payment',
                this.g.user.wallets[0].inkey,
                {
                  payment_hash: paymentHash
                }
              )
            } catch (error) {
              console.error('Error recording payment:', error)
            }

            this.$q.notify({
              type: 'positive',
              message: 'Payment received! Your balance has been updated.',
              timeout: 3000
            })
            this.payDialog.show = false
            this.payDialog.paymentRequest = null
            this.payDialog.amount = null
            await this.loadBalance()
            await this.loadTransactions()
            return true
          }
          return false
        } catch (error) {
          // Silently ignore errors (payment might not exist yet)
          return false
        }
      }

      // Check every 2 seconds for up to 5 minutes
      let attempts = 0
      const maxAttempts = 150 // 5 minutes
      this.payDialog.pollIntervalId = setInterval(async () => {
        attempts++
        const paid = await checkPayment()
        if (paid || attempts >= maxAttempts) {
          clearInterval(this.payDialog.pollIntervalId)
          this.payDialog.pollIntervalId = null
        }
      }, 2000)
    },
    showManualPaymentOption() {
      // This is for when user wants to pay their debt manually
      // For now, just notify them to contact castle
      this.$q.notify({
        type: 'info',
        message: 'Please contact Castle directly to arrange manual payment.',
        timeout: 3000
      })
    },
    showManualPaymentDialog() {
      // This is for when Castle owes user and they want to request manual payment
      this.manualPaymentDialog.amount = Math.abs(this.balance.balance)
      this.manualPaymentDialog.description = ''
      this.manualPaymentDialog.show = true
    },
    async submitManualPaymentRequest() {
      this.manualPaymentDialog.loading = true
      try {
        await LNbits.api.request(
          'POST',
          '/castle/api/v1/manual-payment-request',
          this.g.user.wallets[0].inkey,
          {
            amount: this.manualPaymentDialog.amount,
            description: this.manualPaymentDialog.description
          }
        )
        this.$q.notify({
          type: 'positive',
          message: 'Manual payment request submitted successfully!'
        })
        this.manualPaymentDialog.show = false
        this.manualPaymentDialog.amount = null
        this.manualPaymentDialog.description = ''
        await this.loadManualPaymentRequests()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.manualPaymentDialog.loading = false
      }
    },
    async loadManualPaymentRequests() {
      try {
        // If super user, load all requests; otherwise load user's own requests
        const endpoint = this.isSuperUser
          ? '/castle/api/v1/manual-payment-requests/all'
          : '/castle/api/v1/manual-payment-requests'
        const key = this.isSuperUser
          ? this.g.user.wallets[0].adminkey
          : this.g.user.wallets[0].inkey

        const response = await LNbits.api.request(
          'GET',
          endpoint,
          key,
          this.isSuperUser ? {status: 'pending'} : {}
        )
        this.manualPaymentRequests = response.data
      } catch (error) {
        console.error('Error loading manual payment requests:', error)
      }
    },
    async loadPendingExpenses() {
      try {
        if (!this.isSuperUser) return
        if (!this.g.user.wallets[0]?.adminkey) return

        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/entries/pending',
          this.g.user.wallets[0].adminkey
        )
        this.pendingExpenses = response.data
      } catch (error) {
        console.error('Error loading pending expenses:', error)
      }
    },
    async approveManualPaymentRequest(requestId) {
      try {
        await LNbits.api.request(
          'POST',
          `/castle/api/v1/manual-payment-requests/${requestId}/approve`,
          this.g.user.wallets[0].adminkey
        )
        this.$q.notify({
          type: 'positive',
          message: 'Manual payment request approved!'
        })
        await this.loadManualPaymentRequests()
        await this.loadBalance()
        await this.loadTransactions()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async rejectManualPaymentRequest(requestId) {
      try {
        await LNbits.api.request(
          'POST',
          `/castle/api/v1/manual-payment-requests/${requestId}/reject`,
          this.g.user.wallets[0].adminkey
        )
        this.$q.notify({
          type: 'warning',
          message: 'Manual payment request rejected'
        })
        await this.loadManualPaymentRequests()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async approveExpense(entryId) {
      try {
        await LNbits.api.request(
          'POST',
          `/castle/api/v1/entries/${entryId}/approve`,
          this.g.user.wallets[0].adminkey
        )
        this.$q.notify({
          type: 'positive',
          message: 'Expense approved!'
        })
        await this.loadPendingExpenses()
        await this.loadBalance()
        await this.loadTransactions()
        await this.loadAllUserBalances()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async rejectExpense(entryId) {
      try {
        await LNbits.api.request(
          'POST',
          `/castle/api/v1/entries/${entryId}/reject`,
          this.g.user.wallets[0].adminkey
        )
        this.$q.notify({
          type: 'warning',
          message: 'Expense rejected'
        })
        await this.loadPendingExpenses()
        await this.loadTransactions()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async loadBalanceAssertions() {
      if (!this.isSuperUser) return

      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/assertions',
          this.g.user.wallets[0].adminkey
        )
        this.balanceAssertions = response.data
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async submitAssertion() {
      this.assertionDialog.loading = true
      try {
        const payload = {
          account_id: this.assertionDialog.account_id,
          expected_balance_sats: this.assertionDialog.expected_balance_sats,
          tolerance_sats: this.assertionDialog.tolerance_sats || 0
        }

        // Add fiat balance check if currency selected
        if (this.assertionDialog.fiat_currency) {
          payload.fiat_currency = this.assertionDialog.fiat_currency
          payload.expected_balance_fiat = this.assertionDialog.expected_balance_fiat
          payload.tolerance_fiat = this.assertionDialog.tolerance_fiat || 0
        }

        await LNbits.api.request(
          'POST',
          '/castle/api/v1/assertions',
          this.g.user.wallets[0].adminkey,
          payload
        )

        this.$q.notify({
          type: 'positive',
          message: 'Balance assertion passed!',
          timeout: 3000
        })

        // Reset dialog
        this.assertionDialog = {
          show: false,
          account_id: '',
          expected_balance_sats: 0,
          expected_balance_fiat: null,
          fiat_currency: null,
          tolerance_sats: 0,
          tolerance_fiat: 0,
          loading: false
        }

        // Reload assertions
        await this.loadBalanceAssertions()
      } catch (error) {
        // Check if it's a 409 Conflict (assertion failed)
        if (error.response && error.response.status === 409) {
          const detail = error.response.data.detail
          this.$q.notify({
            type: 'negative',
            message: `Assertion Failed! Expected: ${this.formatSats(detail.expected_sats)} sats, Got: ${this.formatSats(detail.actual_sats)} sats (diff: ${this.formatSats(detail.difference_sats)} sats)`,
            timeout: 5000,
            html: true
          })
          // Still reload to show the failed assertion
          await this.loadBalanceAssertions()
          this.assertionDialog.show = false
        } else {
          LNbits.utils.notifyApiError(error)
        }
      } finally {
        this.assertionDialog.loading = false
      }
    },
    async recheckAssertion(assertionId) {
      try {
        await LNbits.api.request(
          'POST',
          `/castle/api/v1/assertions/${assertionId}/check`,
          this.g.user.wallets[0].adminkey
        )

        this.$q.notify({
          type: 'positive',
          message: 'Assertion re-checked',
          timeout: 2000
        })

        await this.loadBalanceAssertions()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async deleteAssertion(assertionId) {
      try {
        await LNbits.api.request(
          'DELETE',
          `/castle/api/v1/assertions/${assertionId}`,
          this.g.user.wallets[0].adminkey
        )

        this.$q.notify({
          type: 'positive',
          message: 'Assertion deleted',
          timeout: 2000
        })

        await this.loadBalanceAssertions()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    getAccountName(accountId) {
      const account = this.accounts.find(a => a.id === accountId)
      return account ? account.name : accountId
    },
    getUserName(userId) {
      const user = this.users.find(u => u.user_id === userId)
      return user ? user.username : userId.substring(0, 16) + '...'
    },
    async loadReconciliationSummary() {
      if (!this.isSuperUser) return

      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/reconciliation/summary',
          this.g.user.wallets[0].adminkey
        )
        this.reconciliation.summary = response.data
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async loadReconciliationDiscrepancies() {
      if (!this.isSuperUser) return

      try {
        const response = await LNbits.api.request(
          'GET',
          '/castle/api/v1/reconciliation/discrepancies',
          this.g.user.wallets[0].adminkey
        )
        this.reconciliation.discrepancies = response.data
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      }
    },
    async runFullReconciliation() {
      this.reconciliation.checking = true
      try {
        const response = await LNbits.api.request(
          'POST',
          '/castle/api/v1/reconciliation/check-all',
          this.g.user.wallets[0].adminkey
        )

        const results = response.data
        this.$q.notify({
          type: results.failed > 0 ? 'warning' : 'positive',
          message: `Checked ${results.checked} assertions: ${results.passed} passed, ${results.failed} failed`,
          timeout: 3000
        })

        // Reload reconciliation data
        await this.loadReconciliationSummary()
        await this.loadReconciliationDiscrepancies()
        await this.loadBalanceAssertions()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.reconciliation.checking = false
      }
    },
    copyToClipboard(text) {
      navigator.clipboard.writeText(text)
      this.$q.notify({
        type: 'positive',
        message: 'Copied to clipboard!',
        timeout: 1000
      })
    },
    showPayBalanceDialog() {
      // Clear any existing polling
      if (this.payDialog.pollIntervalId) {
        clearInterval(this.payDialog.pollIntervalId)
        this.payDialog.pollIntervalId = null
      }

      this.payDialog.amount = Math.abs(this.balance.balance)
      this.payDialog.paymentRequest = null
      this.payDialog.paymentHash = null
      this.payDialog.checkWalletKey = null
      this.payDialog.show = true
    },
    async showReceivableDialog() {
      // Load users if not already loaded
      if (this.users.length === 0 && this.isSuperUser) {
        await this.loadUsers()
      }
      this.receivableDialog.show = true
    },
    async submitReceivable() {
      this.receivableDialog.loading = true
      try {
        await LNbits.api.request(
          'POST',
          '/castle/api/v1/entries/receivable',
          this.g.user.wallets[0].adminkey,
          {
            description: this.receivableDialog.description,
            amount: this.receivableDialog.amount,
            revenue_account: this.receivableDialog.revenueAccount,
            user_id: this.receivableDialog.selectedUser,
            reference: this.receivableDialog.reference || null,
            currency: this.receivableDialog.currency || null
          }
        )
        this.$q.notify({
          type: 'positive',
          message: 'Receivable added successfully'
        })
        this.receivableDialog.show = false
        this.resetReceivableDialog()
        await this.loadBalance()
        await this.loadTransactions()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.receivableDialog.loading = false
      }
    },
    resetExpenseDialog() {
      this.expenseDialog.description = ''
      this.expenseDialog.amount = null
      this.expenseDialog.expenseAccount = ''
      this.expenseDialog.isEquity = false
      this.expenseDialog.reference = ''
      this.expenseDialog.currency = 'EUR'
      this.expenseDialog.date = new Date().toISOString().split('T')[0]
    },
    resetReceivableDialog() {
      this.receivableDialog.selectedUser = ''
      this.receivableDialog.description = ''
      this.receivableDialog.amount = null
      this.receivableDialog.revenueAccount = ''
      this.receivableDialog.reference = ''
      this.receivableDialog.currency = null
    },
    showSettleReceivableDialog(userBalance) {
      // Only show for users who owe castle (negative balance)
      if (userBalance.balance >= 0) return

      // Clear any existing polling
      if (this.settleReceivableDialog.pollIntervalId) {
        clearInterval(this.settleReceivableDialog.pollIntervalId)
      }

      // Extract fiat balances (e.g., EUR)
      const fiatBalances = userBalance.fiat_balances || {}
      const fiatCurrency = Object.keys(fiatBalances)[0] || null // Get first fiat currency (e.g., 'EUR')
      const fiatAmount = fiatCurrency ? Math.abs(fiatBalances[fiatCurrency]) : 0

      this.settleReceivableDialog = {
        show: true,
        user_id: userBalance.user_id,
        username: userBalance.username,
        maxAmount: Math.abs(userBalance.balance), // Sats amount
        maxAmountFiat: fiatAmount, // EUR or other fiat amount
        fiatCurrency: fiatCurrency, // 'EUR', 'USD', etc.
        amount: fiatCurrency ? fiatAmount : Math.abs(userBalance.balance), // Default to fiat if available, otherwise sats
        payment_method: fiatCurrency ? 'cash' : 'lightning', // Default to cash if fiat balance exists
        description: '', // Will be auto-generated based on payment method if left empty
        reference: '',
        loading: false,
        invoice: null,
        paymentHash: null,
        checkWalletKey: null,
        pollIntervalId: null,
        exchangeRate: fiatAmount > 0 ? Math.abs(userBalance.balance) / fiatAmount : this.currentExchangeRate, // Calculate rate from actual amounts or use current rate
        originalCurrency: fiatCurrency || 'BTC'
      }
    },
    async generateSettlementInvoice() {
      this.settleReceivableDialog.loading = true

      // Clear any existing polling interval
      if (this.settleReceivableDialog.pollIntervalId) {
        clearInterval(this.settleReceivableDialog.pollIntervalId)
        this.settleReceivableDialog.pollIntervalId = null
      }

      try {
        // Generate an invoice on the Castle wallet for the user to pay
        const response = await LNbits.api.request(
          'POST',
          '/castle/api/v1/generate-payment-invoice',
          this.g.user.wallets[0].adminkey,
          {
            amount: this.settleReceivableDialog.amount,
            user_id: this.settleReceivableDialog.user_id  // Specify which user this invoice is for
          }
        )

        // Store invoice details
        this.settleReceivableDialog.invoice = response.data.payment_request
        this.settleReceivableDialog.paymentHash = response.data.payment_hash
        this.settleReceivableDialog.checkWalletKey = response.data.check_wallet_key

        this.$q.notify({
          type: 'positive',
          message: 'Lightning invoice generated! User can scan QR code or copy to pay.',
          timeout: 3000
        })

        // Start polling for payment
        this.pollForSettlementPayment(
          response.data.payment_hash,
          response.data.check_wallet_key
        )
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.settleReceivableDialog.loading = false
      }
    },
    async pollForSettlementPayment(paymentHash, checkWalletKey) {
      // Clear any existing interval
      if (this.settleReceivableDialog.pollIntervalId) {
        clearInterval(this.settleReceivableDialog.pollIntervalId)
      }

      // Poll every 2 seconds for payment status
      const checkPayment = async () => {
        try {
          const response = await LNbits.api.request(
            'GET',
            `/api/v1/payments/${paymentHash}`,
            checkWalletKey
          )

          if (response.data && response.data.paid) {
            // Stop polling immediately
            clearInterval(this.settleReceivableDialog.pollIntervalId)
            this.settleReceivableDialog.pollIntervalId = null

            // Record payment in accounting - this creates the journal entry
            // that settles the receivable
            try {
              const recordResponse = await LNbits.api.request(
                'POST',
                '/castle/api/v1/record-payment',
                this.g.user.wallets[0].adminkey,
                {
                  payment_hash: paymentHash
                }
              )
              console.log('Settlement payment recorded:', recordResponse.data)

              this.$q.notify({
                type: 'positive',
                message: 'Payment received! Receivable has been settled.',
                timeout: 3000
              })

              // Close dialog and refresh
              this.settleReceivableDialog.show = false
              await this.loadBalance()
              await this.loadTransactions()
              await this.loadAllUserBalances()
            } catch (error) {
              console.error('Error recording settlement payment:', error)
              this.$q.notify({
                type: 'negative',
                message: 'Payment detected but failed to record: ' + (error.response?.data?.detail || error.message),
                timeout: 5000
              })
            }
            return true
          }
          return false
        } catch (error) {
          // Silently ignore errors (payment might not exist yet)
          return false
        }
      }

      // Check every 2 seconds for up to 5 minutes
      let attempts = 0
      const maxAttempts = 150 // 5 minutes
      this.settleReceivableDialog.pollIntervalId = setInterval(async () => {
        attempts++
        const paid = await checkPayment()
        if (paid || attempts >= maxAttempts) {
          clearInterval(this.settleReceivableDialog.pollIntervalId)
          this.settleReceivableDialog.pollIntervalId = null
        }
      }, 2000)
    },
    async submitSettleReceivable() {
      this.settleReceivableDialog.loading = true
      try {
        // Determine if this is a fiat payment
        const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
          this.settleReceivableDialog.payment_method
        )

        // Create description with payment method
        const paymentMethodLabels = {
          'cash': 'Cash payment',
          'bank_transfer': 'Bank transfer',
          'check': 'Check payment',
          'lightning': 'Lightning payment',
          'other': 'Payment'
        }
        const methodLabel = paymentMethodLabels[this.settleReceivableDialog.payment_method] || 'Payment'
        const description = this.settleReceivableDialog.description ||
                          `${methodLabel} from ${this.settleReceivableDialog.username}`

        const payload = {
          user_id: this.settleReceivableDialog.user_id,
          amount: this.settleReceivableDialog.amount,
          payment_method: this.settleReceivableDialog.payment_method,
          description: description,
          reference: this.settleReceivableDialog.reference || null,
        }

        // Add currency info for fiat payments
        if (isCashPayment && this.settleReceivableDialog.fiatCurrency) {
          payload.currency = this.settleReceivableDialog.fiatCurrency
          payload.amount_sats = this.settleReceivableDialog.maxAmount
        }

        const response = await LNbits.api.request(
          'POST',
          '/castle/api/v1/receivables/settle',
          this.g.user.wallets[0].adminkey,
          payload
        )

        this.$q.notify({
          type: 'positive',
          message: response.data.message,
          timeout: 3000
        })

        this.settleReceivableDialog.show = false

        // Reload balances
        await this.loadBalance()
        await this.loadTransactions()
        await this.loadAllUserBalances()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.settleReceivableDialog.loading = false
      }
    },
    showPayUserDialog(userBalance) {
      // Only show for users castle owes (positive balance)
      if (userBalance.balance <= 0) return

      // Extract fiat balances (e.g., EUR)
      const fiatBalances = userBalance.fiat_balances || {}
      const fiatCurrency = Object.keys(fiatBalances)[0] || null
      const fiatAmount = fiatCurrency ? fiatBalances[fiatCurrency] : 0

      this.payUserDialog = {
        show: true,
        user_id: userBalance.user_id,
        username: userBalance.username,
        maxAmount: userBalance.balance, // Positive sats amount castle owes
        maxAmountFiat: fiatAmount, // EUR or other fiat amount
        fiatCurrency: fiatCurrency,
        amount: fiatCurrency ? fiatAmount : userBalance.balance, // Default to fiat if available
        payment_method: 'lightning', // Default to lightning for paying
        description: '',
        reference: '',
        loading: false,
        paymentSuccess: false,
        exchangeRate: fiatAmount > 0 ? userBalance.balance / fiatAmount : this.currentExchangeRate,
        originalCurrency: fiatCurrency || 'BTC'
      }
    },
    async sendLightningPayment() {
      this.payUserDialog.loading = true
      try {
        // Request an invoice from the user's wallet
        const userWallet = await this.getUserWallet(this.payUserDialog.user_id)

        if (!userWallet || !userWallet.user_wallet_id) {
          throw new Error('User has not configured their wallet. Ask them to set up their wallet first.')
        }

        // Generate invoice on user's wallet
        const invoiceResponse = await LNbits.api.request(
          'POST',
          `/api/v1/payments`,
          userWallet.user_wallet_id_invoice_key,
          {
            out: false,
            amount: this.payUserDialog.amount,
            memo: `Payment from Castle to ${this.payUserDialog.username}`
          }
        )

        const paymentRequest = invoiceResponse.data.payment_request

        // Pay the invoice from Castle's wallet
        const paymentResponse = await LNbits.api.request(
          'POST',
          `/api/v1/payments`,
          this.g.user.wallets[0].adminkey,
          {
            out: true,
            bolt11: paymentRequest
          }
        )

        // Record the payment in Castle accounting
        await LNbits.api.request(
          'POST',
          '/castle/api/v1/payables/pay',
          this.g.user.wallets[0].adminkey,
          {
            user_id: this.payUserDialog.user_id,
            amount: this.payUserDialog.amount,
            payment_method: 'lightning',
            payment_hash: paymentResponse.data.payment_hash
          }
        )

        this.payUserDialog.paymentSuccess = true

        this.$q.notify({
          type: 'positive',
          message: `Successfully sent ${this.formatSats(this.payUserDialog.amount)} sats to ${this.payUserDialog.username}`,
          timeout: 3000
        })

        // Reload balances after a short delay
        setTimeout(async () => {
          await this.loadBalance()
          await this.loadTransactions()
          await this.loadAllUserBalances()
          this.payUserDialog.show = false
        }, 2000)

      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.payUserDialog.loading = false
      }
    },
    async submitPayUser() {
      this.payUserDialog.loading = true
      try {
        const isCashPayment = ['cash', 'bank_transfer', 'check'].includes(
          this.payUserDialog.payment_method
        )

        // Create description with payment method
        const paymentMethodLabels = {
          'cash': 'Cash payment',
          'bank_transfer': 'Bank transfer',
          'check': 'Check payment',
          'other': 'Payment'
        }
        const methodLabel = paymentMethodLabels[this.payUserDialog.payment_method] || 'Payment'
        const description = this.payUserDialog.description ||
                          `${methodLabel} to ${this.payUserDialog.username}`

        const payload = {
          user_id: this.payUserDialog.user_id,
          amount: this.payUserDialog.amount,
          payment_method: this.payUserDialog.payment_method,
          description: description,
          reference: this.payUserDialog.reference || null,
        }

        // Add currency info for fiat payments
        if (isCashPayment && this.payUserDialog.fiatCurrency) {
          payload.currency = this.payUserDialog.fiatCurrency
          payload.amount_sats = this.payUserDialog.maxAmount
        }

        const response = await LNbits.api.request(
          'POST',
          '/castle/api/v1/payables/pay',
          this.g.user.wallets[0].adminkey,
          payload
        )

        this.$q.notify({
          type: 'positive',
          message: response.data.message,
          timeout: 3000
        })

        this.payUserDialog.show = false

        // Reload balances
        await this.loadBalance()
        await this.loadTransactions()
        await this.loadAllUserBalances()
      } catch (error) {
        LNbits.utils.notifyApiError(error)
      } finally {
        this.payUserDialog.loading = false
      }
    },
    async getUserWallet(userId) {
      try {
        const response = await LNbits.api.request(
          'GET',
          `/castle/api/v1/user-wallet/${userId}`,
          this.g.user.wallets[0].adminkey
        )
        return response.data
      } catch (error) {
        console.error('Error fetching user wallet:', error)
        return null
      }
    },
    async loadExchangeRate() {
      try {
        // Fetch current BTC/EUR rate from CoinGecko API
        const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=eur')
        const data = await response.json()

        if (data && data.bitcoin && data.bitcoin.eur) {
          // Convert BTC/EUR to sats/EUR (1 BTC = 100,000,000 sats)
          const btcPerEur = 1 / data.bitcoin.eur
          this.currentExchangeRate = Math.round(btcPerEur * 100000000)
          console.log('Exchange rate loaded:', this.currentExchangeRate, 'sats per EUR')
        } else {
          throw new Error('Invalid response from exchange rate API')
        }
      } catch (error) {
        console.error('Error loading exchange rate:', error)
        this.currentExchangeRate = null
        this.$q.notify({
          type: 'warning',
          message: 'Failed to load exchange rate. Fiat currency conversions may not be available.',
          timeout: 5000
        })
      }
    },
    formatSats(amount) {
      return new Intl.NumberFormat().format(amount)
    },
    formatFiat(amount, currency) {
      return new Intl.NumberFormat('en-US', {
        style: 'currency',
        currency: currency,
        minimumFractionDigits: 2,
        maximumFractionDigits: 2
      }).format(amount)
    },
    formatDate(dateString) {
      return new Date(dateString).toLocaleDateString()
    },
    getTotalAmount(entry) {
      if (!entry.lines || entry.lines.length === 0) return 0
      return entry.lines.reduce((sum, line) => sum + line.debit + line.credit, 0) / 2
    },
    getEntryFiatAmount(entry) {
      // Extract fiat amount from metadata if available
      if (!entry.lines || entry.lines.length === 0) return null

      for (const line of entry.lines) {
        if (line.metadata && line.metadata.fiat_currency && line.metadata.fiat_amount) {
          return this.formatFiat(line.metadata.fiat_amount, line.metadata.fiat_currency)
        }
      }
      return null
    },
    isReceivable(entry) {
      // Check if this is a receivable entry (user owes castle)
      // Receivables have a debit to an "Accounts Receivable" account with the user's ID
      if (!entry.lines || entry.lines.length === 0) return false

      for (const line of entry.lines) {
        // Look for a line with positive debit on an accounts receivable account
        if (line.debit > 0) {
          // Check if the account is associated with this user's receivables
          const account = this.accounts.find(a => a.id === line.account_id)
          if (account && account.name && account.name.includes('Assets:Receivable') && account.account_type === 'asset') {
            return true
          }
        }
      }
      return false
    },
    isPayable(entry) {
      // Check if this is a payable entry (castle owes user)
      // Payables have a credit to an "Accounts Payable" account with the user's ID
      if (!entry.lines || entry.lines.length === 0) return false

      for (const line of entry.lines) {
        // Look for a line with positive credit on an accounts payable account
        if (line.credit > 0) {
          // Check if the account is associated with this user's payables
          const account = this.accounts.find(a => a.id === line.account_id)
          if (account && account.name && account.name.includes('Liabilities:Payable') && account.account_type === 'liability') {
            return true
          }
        }
      }
      return false
    }
  },
  async created() {
    // Load settings first to determine if user is super user
    await this.loadSettings()
    await this.loadUserWallet()
    await this.loadExchangeRate()
    await this.loadBalance()
    await this.loadTransactions()
    await this.loadAccounts()
    await this.loadCurrencies()
    await this.loadManualPaymentRequests()
    // Load users and pending expenses if super user
    if (this.isSuperUser) {
      await this.loadUsers()
      await this.loadPendingExpenses()
      await this.loadBalanceAssertions()
      await this.loadReconciliationSummary()
      await this.loadReconciliationDiscrepancies()
    }
  }
})
