import { ref, computed } from 'vue'
import { BaseService } from '@/core/base/BaseService'
import { payInvoiceWithWallet } from '@/lib/api/events'
import { toast } from 'vue-sonner'

export interface PaymentResult {
  payment_hash: string
  fee_msat: number
  preimage: string
}

export interface QRCodeOptions {
  width?: number
  margin?: number
  darkColor?: string
  lightColor?: string
}

export interface PaymentOptions {
  successMessage?: string
  errorMessage?: string
  showToast?: boolean
}

/**
 * Centralized Payment Service
 * Handles Lightning payments, QR code generation, and wallet management
 */
export class PaymentService extends BaseService {
  // Service metadata
  protected readonly metadata = {
    name: 'PaymentService',
    version: '1.0.0',
    dependencies: ['AuthService']
  }

  // Payment state
  private _isProcessingPayment = ref(false)
  private _paymentError = ref<string | null>(null)

  // Public reactive state
  public readonly isProcessingPayment = computed(() => this._isProcessingPayment.value)
  public readonly paymentError = computed(() => this._paymentError.value)

  /**
   * Service-specific initialization (called by BaseService)
   */
  protected async onInitialize(): Promise<void> {
    // Reset payment state on initialization to prevent stuck states
    this.resetPaymentState()
    this.debug('PaymentService initialized with clean state')
  }


  /**
   * Get user wallets from authenticated user
   */
  get userWallets() {
    return this.authService?.user?.value?.wallets || []
  }

  /**
   * Get total balance across all user wallets in millisatoshis
   */
  get totalBalance(): number {
    return this.userWallets.reduce((total: number, wallet: any) => {
      return total + (wallet.balance_msat || 0)
    }, 0)
  }

  /**
   * Check if user has any wallet with balance
   */
  get hasWalletWithBalance(): boolean {
    return this.userWallets.some((wallet: any) => wallet.balance_msat > 0)
  }

  /**
   * Find wallet with sufficient balance for payment
   */
  getWalletWithBalance(requiredAmountSats?: number): any | null {
    const wallets = this.userWallets
    if (!wallets.length) return null

    if (requiredAmountSats) {
      // Convert sats to msat for comparison
      const requiredMsat = requiredAmountSats * 1000
      return wallets.find((wallet: any) => wallet.balance_msat >= requiredMsat)
    }
    
    return wallets.find((wallet: any) => wallet.balance_msat > 0)
  }

  /**
   * Get the preferred wallet for operations (always use wallets[0] for consistency)
   * This ensures consistent wallet selection across all modules
   */
  getPreferredWallet(): any | null {
    const wallets = this.userWallets
    if (!wallets.length) return null
    return wallets[0]
  }

  /**
   * Get the preferred wallet's admin key for administrative operations
   */
  getPreferredWalletAdminKey(): string | null {
    const wallet = this.getPreferredWallet()
    return wallet?.adminkey || null
  }

  /**
   * Get the preferred wallet's invoice key for read-only operations
   */
  getPreferredWalletInvoiceKey(): string | null {
    const wallet = this.getPreferredWallet()
    return wallet?.inkey || null
  }

  /**
   * Update wallet balance from WebSocket notifications
   * @param balanceMsat - The new balance in millisatoshis
   * @param walletId - Optional wallet ID (defaults to preferred wallet)
   */
  updateWalletBalance(balanceMsat: number, walletId?: string): void {
    if (!this.authService?.user?.value?.wallets?.length) {
      this.debug('No wallets available to update')
      return
    }

    // Determine which wallet to update
    let walletToUpdate
    if (walletId) {
      walletToUpdate = this.authService.user.value.wallets.find((w: any) => w.id === walletId)
    } else {
      // Use preferred wallet if no ID specified
      walletToUpdate = this.getPreferredWallet()
    }

    if (walletToUpdate) {
      const oldBalance = walletToUpdate.balance_msat
      walletToUpdate.balance_msat = balanceMsat

      // Trigger reactivity in AuthService
      this.authService.user.value = { ...this.authService.user.value }

      this.debug(`Wallet ${walletToUpdate.id} balance updated: ${oldBalance} -> ${balanceMsat} msat (${Math.round(balanceMsat/1000)} sats)`)
    } else {
      this.debug(`Wallet ${walletId} not found for balance update`)
    }
  }

  /**
   * Generate QR code for Lightning payment request
   */
  async generateQRCode(
    paymentRequest: string, 
    options: QRCodeOptions = {}
  ): Promise<string> {
    try {
      const qrcode = await import('qrcode')
      const dataUrl = await qrcode.toDataURL(paymentRequest, {
        width: options.width || 256,
        margin: options.margin || 2,
        color: {
          dark: options.darkColor || '#000000',
          light: options.lightColor || '#FFFFFF'
        }
      })
      return dataUrl
    } catch (error) {
      const err = this.handleError(error, 'generateQRCode')
      throw err
    }
  }

  /**
   * Generate QR code for ticket or other custom data
   */
  async generateCustomQRCode(
    data: string, 
    options: QRCodeOptions = {}
  ): Promise<string> {
    try {
      const qrcode = await import('qrcode')
      const dataUrl = await qrcode.toDataURL(data, {
        width: options.width || 128,
        margin: options.margin || 2,
        color: {
          dark: options.darkColor || '#000000',
          light: options.lightColor || '#FFFFFF'
        }
      })
      return dataUrl
    } catch (error) {
      const err = this.handleError(error, 'generateCustomQRCode')
      throw err
    }
  }

  /**
   * Pay Lightning invoice with user's wallet
   */
  async payWithWallet(
    paymentRequest: string,
    requiredAmountSats?: number,
    options: PaymentOptions = {}
  ): Promise<PaymentResult> {
    // Check authentication
    if (!this.authService?.isAuthenticated?.value || !this.authService?.user?.value) {
      throw new Error('User must be authenticated to pay with wallet')
    }

    // Find suitable wallet
    const wallet = this.getWalletWithBalance(requiredAmountSats)
    if (!wallet) {
      throw new Error('No wallet with sufficient balance found')
    }

    try {
      this._isProcessingPayment.value = true
      this._paymentError.value = null

      this.debug(`Paying invoice with wallet: ${wallet.id.slice(0, 8)}`)

      // Make payment
      const paymentResult = await payInvoiceWithWallet(
        paymentRequest, 
        wallet.id, 
        wallet.adminkey
      )
      
      this.debug('Payment successful', {
        paymentHash: paymentResult.payment_hash,
        feeMsat: paymentResult.fee_msat
      })

      // Show success notification if enabled
      if (options.showToast !== false) {
        const message = options.successMessage || 'Payment successful!'
        toast.success(message)
      }

      return paymentResult
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Payment failed'
      this._paymentError.value = errorMessage
      
      this.debug('Payment failed', error)
      
      // Show error notification if enabled
      if (options.showToast !== false) {
        const message = options.errorMessage || errorMessage
        toast.error('Payment failed', {
          description: message
        })
      }
      
      throw error
    } finally {
      this._isProcessingPayment.value = false
    }
  }

  /**
   * Open external Lightning wallet
   */
  openExternalWallet(paymentRequest: string): void {
    if (!paymentRequest) {
      toast.error('No payment request available')
      return
    }

    try {
      const lightningUrl = `lightning:${paymentRequest}`
      window.open(lightningUrl, '_blank')
      
      toast.info('Opening Lightning wallet...', {
        description: 'If no wallet opens, copy the payment request manually'
      })
    } catch (error) {
      console.warn('Failed to open lightning: URL:', error)
      
      // Fallback: copy to clipboard
      navigator.clipboard?.writeText(paymentRequest).then(() => {
        toast.success('Payment request copied to clipboard')
      }).catch(() => {
        toast.info('Please copy the payment request manually')
      })
    }
  }

  /**
   * Handle payment with automatic fallback
   * Tries wallet payment first, falls back to external wallet
   */
  async handlePayment(
    paymentRequest: string,
    requiredAmountSats?: number,
    options: PaymentOptions = {}
  ): Promise<PaymentResult | null> {
    if (!paymentRequest) {
      toast.error('No payment request available')
      return null
    }

    // Try wallet payment first if user has balance
    if (this.hasWalletWithBalance) {
      try {
        return await this.payWithWallet(
          paymentRequest, 
          requiredAmountSats, 
          options
        )
      } catch (error) {
        this.debug('Wallet payment failed, offering external wallet option:', error)
        // Don't throw here, continue to external wallet option
      }
    }

    // Fallback to external wallet
    this.openExternalWallet(paymentRequest)
    return null // External wallet payment status unknown
  }

  /**
   * Clear payment error state
   */
  clearPaymentError(): void {
    this._paymentError.value = null
  }

  /**
   * Reset payment state
   */
  resetPaymentState(): void {
    this._isProcessingPayment.value = false
    this._paymentError.value = null
    this.debug('Payment state reset to clean state')
  }

  /**
   * Force reset payment state (public method for debugging)
   */
  forceResetPaymentState(): void {
    console.log('Force resetting payment state from:', this._isProcessingPayment.value)
    this._isProcessingPayment.value = false
    this._paymentError.value = null
    console.log('Payment state after force reset:', this._isProcessingPayment.value)
  }

  /**
   * Cleanup when service is disposed (called by BaseService)
   */
  protected async onDispose(): Promise<void> {
    this.resetPaymentState()
    this.debug('PaymentService disposed')
  }
}

// Export singleton instance
export const paymentService = new PaymentService()