import { toValue, ref } from 'vue'
import { createStripeElements } from '~/composables/useStripeElements'
import { opnFetch } from '~/composables/useOpnApi.js'
// Assume Stripe is loaded globally or via another mechanism if needed client-side
// For server-side/Nuxt API routes, import Stripe library properly.

/**
 * @fileoverview Composable for handling payment processing, currently focused on Stripe.
 */
export function useFormPayment(formConfig, form) {
  const stripeElements = ref(null)
  
  /**
   * Gets payment-related data for a specific payment block
   * @param {Object} paymentBlock - The payment field configuration
   * @returns {Object|null} Payment data including stripeElements or null if not applicable
   */
  const getPaymentData = (paymentBlock) => {
    if (!import.meta.client || !paymentBlock || paymentBlock.type !== 'payment') return null
    
    // Create Stripe elements if needed and this is a Stripe payment
    if (paymentBlock.provider === 'stripe' || !paymentBlock.provider) {
      // Ensure account ID is a string (Stripe.js requires a string)
      const accountId = paymentBlock.stripe_account_id ? String(paymentBlock.stripe_account_id) : null
      
      if (!stripeElements.value) {
        // Create the Stripe elements with the account ID
        stripeElements.value = createStripeElements(accountId)
      } else if (stripeElements.value && accountId) {
        // Update the account ID if the instance already exists
        // Use the proper setter method to avoid readonly errors
        if (typeof stripeElements.value.setAccountId === 'function') {
          stripeElements.value.setAccountId(accountId)
        }
      }
      
      return {
        stripeElements: stripeElements.value,
        oauthProviderId: accountId
      }
    }
    return null
  }

  /**
   * Creates a payment intent with the Stripe API using a POST request.
   * @param {Number} amount - The amount to charge in cents.
   * @param {String} currency - The currency code (e.g., 'usd').
   * @param {String} description - A description for the payment.
   * @returns {Promise<Object>} The result of creating the payment intent.
   */
  const _createPaymentIntent = async (_amount, _currency, _description) => {
    if (!import.meta.client) {
      return { success: false, error: 'Client-side only operation' }
    }

    try {
      
      // Get form slug from config
      const config = toValue(formConfig)
      const formSlug = config.slug
      
      if (!formSlug) {
        console.error('Missing form slug in config')
        return { success: false, error: 'Invalid form configuration' }
      }
      
      // Construct the URL (no query params needed for POST)
      const url = `/forms/${formSlug}/stripe-connect/payment-intent`
      
      // Use opnFetch with POST method and an empty body
      const response = await opnFetch(url, {
        method: 'POST',
        body: {}
      })
      
      // Handle response structure with type and intent fields
      if (response?.type === 'success' && response?.intent?.secret) {
        return {
          success: true,
          client_secret: response.intent.secret,
          intentId: response.intent.id
        }
      }
      
      // Handle error response
      return { 
        success: false, 
        error: response?.message || 'Could not create payment: Invalid response from server' 
      }
    } catch (error) {
      return {
        success: false,
        error: error.message || 'Failed to create payment'
      }
    }
  }

  /**
   * Confirms the Stripe payment on the client-side using Stripe.js.
   * @param {String} clientSecret - The Stripe client secret.
   * @param {String} paymentBlockId - The ID of the payment block for setting errors.
   * @returns {Promise<Object>} The result of the payment confirmation.
   */
  const _confirmStripePayment = async (clientSecret, paymentBlockId) => {
    if (!import.meta.client) {
      return { success: false, error: 'Client-side only operation' }
    }
    
    if (!stripeElements.value || !stripeElements.value.state) {
      return { success: false, error: 'Stripe elements not initialized' }
    }
    
    const state = stripeElements.value.state
    const { stripe, card } = state
    
    if (!stripe || !card) {
      const error = 'Stripe or card element not available'
      if (paymentBlockId) form.errors.set(paymentBlockId, error)
      return { success: false, error }
    }
    
    try {      
      const result = await stripe.confirmCardPayment(clientSecret, {
        payment_method: {
          card: card,
          billing_details: {
            name: state.cardHolderName || '',
            email: state.cardHolderEmail || ''
          }
        },
        receipt_email: state.cardHolderEmail
      })
      
      // Check for errors
      if (result.error) {
        console.error('Payment confirmation error:', result.error)
        const errorMessage = result.error.message || 'Payment failed. Please try again.'
        
        if (paymentBlockId) {
          form.errors.set(paymentBlockId, errorMessage)
        }
        
        return { 
          success: false, 
          error: errorMessage,
          code: result.error.code,
          type: result.error.type 
        }
      }
      
      // Handle payment intent status
      if (result.paymentIntent) {
        const status = result.paymentIntent.status
        const intentId = result.paymentIntent.id
        
        // Store successful payment intent ID
        if (status === 'succeeded' || status === 'processing') {
          // Update form data with payment information
          const updateData = {}
          updateData['stripe_payment_intent_id'] = intentId
          updateData['payment_status'] = status
          
          // Update payment block field with intent ID
          if (paymentBlockId) {
            updateData[paymentBlockId] = intentId
          }
          
          // Update form data
          form.update(updateData)
          
          // Also update the Stripe state
          if (state.intentId !== intentId && stripeElements.value.setIntentId) {
            stripeElements.value.setIntentId(intentId)
          }
          
          return { 
            success: true, 
            paymentIntent: result.paymentIntent,
            status: status,
            intentId: intentId
          }
        } else {
          // Payment intent exists but status is not successful
          const failMessage = `Payment failed with status: ${status}`
          console.error(failMessage)
          
          if (paymentBlockId) {
            form.errors.set(paymentBlockId, failMessage)
          }
          
          return { success: false, error: failMessage }
        }
      }
      
      // If we get here, something unexpected happened
      const unexpectedError = 'Payment failed with an unexpected error'
      if (paymentBlockId) {
        form.errors.set(paymentBlockId, unexpectedError)
      }
      
      return { success: false, error: unexpectedError }
      
    } catch (error) {
      console.error('Payment confirmation error:', error)
      
      const errorMessage = error.message || 'Payment confirmation failed'
      
      if (paymentBlockId) {
        form.errors.set(paymentBlockId, errorMessage)
      }
      
      return { 
        success: false, 
        error: errorMessage,
        code: error.code,
        type: error.type
      }
    }
  }

  /**
   * Process a payment for the form
   * @param {Object} paymentBlock - The payment block from the form config
   * @param {Boolean} isRequired - Whether payment is required
   * @returns {Promise<Object>} The result of the payment processing
   */
  const processPayment = async (paymentBlock, isRequired = true) => {
    // Only process payments on the client side
    if (!import.meta.client) {
      console.warn('Payment processing attempted on server')
      return { success: false, error: 'Payment can only be processed in the browser' }
    }

    // Validate the payment block
    if (!paymentBlock || paymentBlock.type !== 'payment') {
      console.error('Invalid payment block provided:', paymentBlock)
      return { success: false, error: 'Invalid payment block' }
    }

    const paymentBlockId = paymentBlock.id

    // First check for existing payment in form data
    const existingPaymentId = form[paymentBlockId]
    if (existingPaymentId && isPaymentIntentId(existingPaymentId)) {
      return { success: true, intentId: existingPaymentId }
    }

    // Check if Stripe elements are initialized
    if (!stripeElements.value || !stripeElements.value.state) {
      console.error('Stripe elements not initialized')
      if (paymentBlockId) form.errors.set(paymentBlockId, 'Payment system not ready')
      return { success: false, error: 'Stripe elements not initialized' }
    }

    const state = stripeElements.value.state
    const { stripe, card } = state

    // Check if Stripe is loaded
    if (!stripe) {
      const error = 'Stripe.js not initialized'
      console.error(error)
      if (paymentBlockId) form.errors.set(paymentBlockId, error)
      return { success: false, error }
    }

    // Check if card is complete
    const cardComplete = card && !card._empty
    if (!cardComplete) {
      // If payment is not required and card is empty, just skip payment
      if (!isRequired) {
        return { success: true, skipped: true }
      }
      
      const error = 'Please enter your card details'
      if (paymentBlockId) form.errors.set(paymentBlockId, error)
      return { success: false, error }
    }

    // Validate billing details
    if (!state.cardHolderName) {
      const error = 'Please enter the name on your card'
      if (paymentBlockId) form.errors.set(paymentBlockId, error)
      return { success: false, error }
    }

    if (!state.cardHolderEmail) {
      const error = 'Please enter your billing email'
      if (paymentBlockId) form.errors.set(paymentBlockId, error)
      return { success: false, error }
    }

    try {
      // Step 1: Create payment intent
      const config = toValue(formConfig)
      const formSlug = config.slug
      
      if (!formSlug) {
        const error = 'Missing form slug'
        if (paymentBlockId) form.errors.set(paymentBlockId, error)
        return { success: false, error }
      }
      
      // Create payment intent
      const intentResult = await _createPaymentIntent(
        paymentBlock.amount,
        paymentBlock.currency || 'usd',
        paymentBlock.description || ''
      )
      
      if (!intentResult.success || !intentResult.client_secret) {
        const error = intentResult.error || 'Failed to create payment intent'
        console.error('Payment intent creation failed:', error)
        if (paymentBlockId) form.errors.set(paymentBlockId, error)
        return { success: false, error }
      }
      
      // Step 2: Confirm payment with Stripe
      const confirmResult = await _confirmStripePayment(intentResult.client_secret, paymentBlockId)
      
      // Return the result from confirmation
      return confirmResult
      
    } catch (error) {
      console.error('Payment processing error:', error)
      const errorMessage = error.message || 'Payment processing failed'
      if (paymentBlockId) form.errors.set(paymentBlockId, errorMessage)
      return { success: false, error: errorMessage }
    }
  }

  /**
   * Confirms a Stripe payment with given client secret.
   * This method is available for direct usage if needed.
   * @param {String} clientSecret - The client secret from a payment intent
   * @param {String} [paymentBlockId] - Optional ID of payment block for error display
   * @returns {Promise<Object>} The result of payment confirmation
   */
  const confirmStripePayment = async (clientSecret, paymentBlockId) => {
    if (!clientSecret) {
      console.error('Missing client secret for payment confirmation')
      return { success: false, error: 'Invalid payment data' }
    }
    
    return await _confirmStripePayment(clientSecret, paymentBlockId)
  }

  // Helper function to check if a value looks like a Stripe payment intent ID
  const isPaymentIntentId = (value) => {
    return typeof value === 'string' && value.startsWith('pi_')
  }

  // Expose the main payment processing function
  return {
    processPayment,
    getPaymentData,
    createPaymentIntent: _createPaymentIntent,
    confirmStripePayment
  }
} 