import { ref, computed } from 'vue'
import { BaseService } from '@/core/base/BaseService'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import { config } from '@/lib/config'

export interface PayLink {
  id: string
  wallet: string
  description: string
  min: number
  max: number
  comment_chars: number
  username?: string
  lnurl?: string
  lnaddress?: string
}

export interface SendPaymentRequest {
  amount: number
  destination: string // Can be invoice, lnurl, or lightning address
  comment?: string
}

export interface CreateInvoiceRequest {
  amount: number
  memo: string
  expiry?: number // Optional expiry in seconds
}

export interface Invoice {
  payment_hash: string
  bolt11: string // The BOLT11 invoice
  payment_request: string // Same as bolt11, for compatibility
  checking_id: string
  amount: number
  memo: string
  time: number
  expiry: number | null
}

export interface PaymentTransaction {
  id: string
  amount: number
  description: string
  timestamp: Date
  type: 'sent' | 'received'
  status: 'pending' | 'confirmed' | 'failed'
  fee?: number
  tag?: string | null
}

export default class WalletService extends BaseService {
  private paymentService: any = null

  // Required metadata for BaseService
  protected readonly metadata = {
    name: 'WalletService',
    version: '1.0.0',
    dependencies: [] // No specific dependencies
  }

  // Reactive state
  private _payLinks = ref<PayLink[]>([])
  private _transactions = ref<PaymentTransaction[]>([])
  private _isCreatingPayLink = ref(false)
  private _isSendingPayment = ref(false)
  private _isCreatingInvoice = ref(false)
  private _error = ref<string | null>(null)

  // Public reactive getters
  readonly payLinks = computed(() => this._payLinks.value)
  readonly transactions = computed(() => this._transactions.value)
  readonly isCreatingPayLink = computed(() => this._isCreatingPayLink.value)
  readonly isSendingPayment = computed(() => this._isSendingPayment.value)
  readonly isCreatingInvoice = computed(() => this._isCreatingInvoice.value)
  readonly error = computed(() => this._error.value)
  
  protected async onInitialize(): Promise<void> {
    try {
      this.paymentService = injectService(SERVICE_TOKENS.PAYMENT_SERVICE)
      if (!this.paymentService) {
        throw new Error('Payment service not available')
      }

      // Load initial data
      await this.loadPayLinks()
      await this.loadTransactions()

      console.log('WalletService initialized successfully')
    } catch (error) {
      console.error('Failed to initialize WalletService:', error)
      this._error.value = error instanceof Error ? error.message : 'Initialization failed'
      throw error
    }
  }
  
  /**
   * Create a new LNURL pay link for receiving payments
   */
  async createReceiveAddress(params: {
    description: string
    minAmount: number
    maxAmount: number
    username?: string
    allowComments?: boolean
  }): Promise<PayLink | null> {
    this._isCreatingPayLink.value = true
    this._error.value = null
    
    try {
      const wallet = this.paymentService?.getPreferredWallet()
      if (!wallet) {
        throw new Error('No wallet available')
      }
      
      const adminKey = this.paymentService?.getPreferredWalletAdminKey()
      if (!adminKey) {
        throw new Error('No admin key available')
      }
      
      // Create pay link via LNbits LNURLP extension API
      const response = await fetch(`${config.api.baseUrl}/lnurlp/api/v1/links`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Api-Key': adminKey
        },
        body: JSON.stringify({
          description: params.description,
          wallet: wallet.id,
          min: params.minAmount,
          max: params.maxAmount,
          comment_chars: params.allowComments ? 200 : 0,
          username: params.username || null,
          disposable: false // Reusable pay link
        })
      })
      
      if (!response.ok) {
        const error = await response.json()
        throw new Error(error.detail || 'Failed to create pay link')
      }
      
      const payLink: PayLink = await response.json()
      
      // Generate the LNURL and Lightning Address
      const baseUrl = config.api.baseUrl
      payLink.lnurl = `${baseUrl}/lnurlp/${payLink.id}`
      
      if (payLink.username) {
        // Extract domain from base URL
        const domain = new URL(baseUrl).hostname
        payLink.lnaddress = `${payLink.username}@${domain}`
      }
      
      this._payLinks.value.unshift(payLink)
      console.log('Created new pay link:', payLink.id)

      return payLink

    } catch (error) {
      console.error('Failed to create receive address:', error)
      this._error.value = error instanceof Error ? error.message : 'Failed to create receive address'
      return null
    } finally {
      this._isCreatingPayLink.value = false
    }
  }
  
  /**
   * Create a Lightning invoice for receiving payments
   */
  async createInvoice(request: CreateInvoiceRequest): Promise<Invoice | null> {
    this._isCreatingInvoice.value = true
    this._error.value = null

    try {
      const invoiceKey = this.paymentService?.getPreferredWalletInvoiceKey()
      if (!invoiceKey) {
        throw new Error('No invoice key available')
      }

      // Create invoice via LNbits payments API
      const response = await fetch(`${config.api.baseUrl}/api/v1/payments`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Api-Key': invoiceKey
        },
        body: JSON.stringify({
          out: false, // Incoming payment (receiving)
          amount: request.amount,
          unit: 'sat',
          memo: request.memo,
          expiry: request.expiry || 3600 // Default 1 hour expiry
        })
      })

      if (!response.ok) {
        const error = await response.json()
        throw new Error(error.detail || 'Failed to create invoice')
      }

      const rawInvoice = await response.json()
      console.log('Raw invoice response:', rawInvoice)

      // Process the response to fix data issues
      const invoice: Invoice = {
        ...rawInvoice,
        payment_request: rawInvoice.bolt11, // Copy bolt11 to payment_request for compatibility
        amount: rawInvoice.amount / 1000, // Convert from millisats to sats
        expiry: rawInvoice.expiry ? this.parseExpiryToSeconds(rawInvoice.expiry) : null
      }

      console.log('Processed invoice:', invoice)
      return invoice

    } catch (error) {
      console.error('Failed to create invoice:', error)
      this._error.value = error instanceof Error ? error.message : 'Failed to create invoice'
      return null
    } finally {
      this._isCreatingInvoice.value = false
    }
  }

  /**
   * Send a Lightning payment
   */
  async sendPayment(request: SendPaymentRequest): Promise<boolean> {
    this._isSendingPayment.value = true
    this._error.value = null
    
    try {
      const adminKey = this.paymentService?.getPreferredWalletAdminKey()
      if (!adminKey) {
        throw new Error('No admin key available')
      }
      
      let endpoint = ''
      let body: any = {}
      
      // Determine payment type and prepare request
      if (request.destination.startsWith('ln')) {
        // Lightning invoice
        endpoint = `${config.api.baseUrl}/api/v1/payments`
        body = {
          out: true,
          bolt11: request.destination
        }
      } else if (request.destination.includes('@') || request.destination.toLowerCase().startsWith('lnurl')) {
        // Lightning address or LNURL
        endpoint = `${config.api.baseUrl}/api/v1/payments/lnurl`
        body = {
          lnurl: request.destination.includes('@') 
            ? `https://${request.destination.split('@')[1]}/.well-known/lnurlp/${request.destination.split('@')[0]}`
            : request.destination,
          amount: request.amount * 1000, // Convert to millisats
          comment: request.comment || ''
        }
      } else {
        throw new Error('Invalid payment destination format')
      }
      
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Api-Key': adminKey
        },
        body: JSON.stringify(body)
      })
      
      if (!response.ok) {
        const error = await response.json()
        throw new Error(error.detail || 'Payment failed')
      }
      
      const payment = await response.json()
      console.log('Payment sent successfully:', payment.payment_hash)

      // Refresh transactions
      await this.loadTransactions()

      return true

    } catch (error) {
      console.error('Failed to send payment:', error)
      this._error.value = error instanceof Error ? error.message : 'Payment failed'
      return false
    } finally {
      this._isSendingPayment.value = false
    }
  }
  
  /**
   * Load existing pay links
   */
  private async loadPayLinks(): Promise<void> {
    try {
      const adminKey = this.paymentService?.getPreferredWalletAdminKey()
      if (!adminKey) return
      
      const response = await fetch(`${config.api.baseUrl}/lnurlp/api/v1/links`, {
        headers: {
          'X-Api-Key': adminKey
        }
      })
      
      if (response.ok) {
        const links = await response.json()
        const baseUrl = config.api.baseUrl
        const domain = new URL(baseUrl).hostname
        
        // Add LNURL and Lightning Address to each link
        this._payLinks.value = links.map((link: PayLink) => ({
          ...link,
          lnurl: `${baseUrl}/lnurlp/${link.id}`,
          lnaddress: link.username ? `${link.username}@${domain}` : undefined
        }))

        console.log(`Loaded ${links.length} pay links`)
      }
    } catch (error) {
      console.error('Failed to load pay links:', error)
    }
  }
  
  /**
   * Load payment transactions
   */
  private async loadTransactions(): Promise<void> {
    try {
      const invoiceKey = this.paymentService?.getPreferredWalletInvoiceKey()
      if (!invoiceKey) return
      
      const response = await fetch(`${config.api.baseUrl}/api/v1/payments`, {
        headers: {
          'X-Api-Key': invoiceKey
        }
      })
      
      if (response.ok) {
        const payments = await response.json()
        
        // Transform to our transaction format
        this._transactions.value = payments.map((payment: any) => {
          let timestamp = new Date()

          if (payment.time) {
            // Check if it's an ISO string or Unix timestamp
            if (typeof payment.time === 'string' && payment.time.includes('T')) {
              // ISO string format (e.g., "2025-09-14T16:49:40.378877+00:00")
              timestamp = new Date(payment.time)
            } else if (typeof payment.time === 'number' || !isNaN(Number(payment.time))) {
              // Unix timestamp (seconds) - multiply by 1000 for milliseconds
              timestamp = new Date(Number(payment.time) * 1000)
            } else {
              // Try to parse as-is
              timestamp = new Date(payment.time)
            }
          }


          return {
            id: payment.payment_hash,
            amount: Math.abs(payment.amount) / 1000,
            description: payment.memo || payment.description || 'No description',
            timestamp: timestamp,
            type: payment.amount > 0 ? 'received' : 'sent',
            status: payment.pending ? 'pending' : 'confirmed',
            fee: payment.fee ? payment.fee / 1000 : undefined,
            tag: payment.tag || (payment.extra && payment.extra.tag) || null
          }
        }).sort((a: PaymentTransaction, b: PaymentTransaction) =>
          b.timestamp.getTime() - a.timestamp.getTime()
        )

        console.log(`Loaded ${payments.length} transactions`)
      }
    } catch (error) {
      console.error('Failed to load transactions:', error)
    }
  }
  
  /**
   * Delete a pay link
   */
  async deletePayLink(linkId: string): Promise<boolean> {
    try {
      const adminKey = this.paymentService?.getPreferredWalletAdminKey()
      if (!adminKey) {
        throw new Error('No admin key available')
      }
      
      const response = await fetch(`${config.api.baseUrl}/lnurlp/api/v1/links/${linkId}`, {
        method: 'DELETE',
        headers: {
          'X-Api-Key': adminKey
        }
      })
      
      if (!response.ok) {
        throw new Error('Failed to delete pay link')
      }
      
      // Remove from local state
      this._payLinks.value = this._payLinks.value.filter(link => link.id !== linkId)
      console.log('Deleted pay link:', linkId)

      return true

    } catch (error) {
      console.error('Failed to delete pay link:', error)
      this._error.value = error instanceof Error ? error.message : 'Failed to delete pay link'
      return false
    }
  }
  
  /**
   * Refresh all data
   */
  async refresh(): Promise<void> {
    await Promise.all([
      this.loadPayLinks(),
      this.loadTransactions()
    ])
  }

  /**
   * Parse expiry date string to seconds from now
   */
  private parseExpiryToSeconds(expiryStr: string): number {
    try {
      const expiryDate = new Date(expiryStr)
      const now = new Date()
      const diffMs = expiryDate.getTime() - now.getTime()
      return Math.max(0, Math.floor(diffMs / 1000)) // Return seconds, minimum 0
    } catch (error) {
      console.error('Failed to parse expiry date:', expiryStr, error)
      return 3600 // Default to 1 hour
    }
  }

  /**
   * Add a new transaction from WebSocket notification
   */
  addTransaction(payment: any): void {
    try {
      const transaction = this.mapPaymentToTransaction(payment)

      // Check if transaction already exists (avoid duplicates)
      const existingIndex = this._transactions.value.findIndex(t => t.id === transaction.id)

      if (existingIndex >= 0) {
        // Update existing transaction
        this._transactions.value[existingIndex] = transaction
      } else {
        // Add new transaction at the beginning (most recent first)
        this._transactions.value = [transaction, ...this._transactions.value]
      }

      console.log('WalletService: Added/updated transaction', transaction)
    } catch (error) {
      console.error('WalletService: Failed to add transaction', error)
    }
  }

  /**
   * Map LNbits payment object to our transaction format
   */
  private mapPaymentToTransaction(payment: any): PaymentTransaction {
    // Handle timestamp parsing - try different formats
    let timestamp = new Date()
    if (payment.time) {
      if (typeof payment.time === 'string') {
        // ISO string format
        timestamp = new Date(payment.time)
      } else if (typeof payment.time === 'number') {
        // Unix timestamp (seconds)
        timestamp = new Date(payment.time * 1000)
      }
    }

    // For the transaction display, convert amount from millisats to sats
    const amountSats = Math.abs(payment.amount) / 1000

    // Map status correctly - be more explicit about the mapping
    let status: 'pending' | 'confirmed' | 'failed' = 'pending'

    // Check for pending first
    if (payment.pending === true) {
      status = 'pending'
    }
    // Check for success status
    else if (payment.status === 'success' || payment.status === 'settled' || payment.status === 'confirmed') {
      status = 'confirmed'
    }
    // Check for failed status
    else if (payment.status === 'failed') {
      status = 'failed'
    }
    // If status is success but no pending field, assume confirmed
    else if (payment.status === 'success' && payment.pending !== true) {
      status = 'confirmed'
    }


    return {
      id: payment.payment_hash || payment.checking_id || payment.id,
      amount: amountSats,
      description: payment.description || payment.memo || 'Payment',
      timestamp: timestamp,
      type: payment.amount > 0 ? 'received' : 'sent',
      status: status,
      fee: payment.fee_msat ? payment.fee_msat / 1000 : undefined,
      tag: payment.tag || null
    }
  }
}
