import { Env } from './env'
import { Logger } from './logger'

let snapLoaded = false
let snapPromise: Promise<void> | null = null

/**
 * Dynamically loads Midtrans Snap.js script
 * Returns a promise that resolves when Snap.js is ready
 */
export function loadSnapScript(): Promise<void> {
  // Return existing promise if already loading
  if (snapPromise) {
    return snapPromise
  }

  // Already loaded
  if (snapLoaded && window.snap) {
    return Promise.resolve()
  }

  // Start loading
  snapPromise = new Promise((resolve, reject) => {
    try {
      const clientKey = Env.MIDTRANS_CLIENT_KEY
      const midtransEnv = Env.MIDTRANS_ENV || 'sandbox'

      if (!clientKey) {
        const error = 'MIDTRANS_CLIENT_KEY not configured'
        Logger.error('snap.load.error', { error })
        reject(new Error(error))
        return
      }

      // Determine Snap.js URL based on environment
      const snapUrl = midtransEnv === 'production'
        ? 'https://app.midtrans.com/snap/snap.js'
        : 'https://app.sandbox.midtrans.com/snap/snap.js'

      Logger.info('snap.load.start', { snapUrl, clientKey: clientKey.substring(0, 10) + '...' })

      // Check if script already exists
      const existingScript = document.querySelector(`script[src="${snapUrl}"]`)
      if (existingScript) {
        Logger.info('snap.load.exists', { snapUrl })
        // Wait a bit and check if window.snap is available
        setTimeout(() => {
          if (window.snap) {
            snapLoaded = true
            Logger.info('snap.load.ready', { hasSnap: true })
            resolve()
          } else {
            Logger.error('snap.load.error', { error: 'Script loaded but window.snap not available' })
            reject(new Error('Snap.js loaded but window.snap not available'))
          }
        }, 500)
        return
      }

      // Create script element
      const script = document.createElement('script')
      script.src = snapUrl
      script.setAttribute('data-client-key', clientKey)
      
      script.onload = () => {
        Logger.info('snap.script.loaded', { snapUrl })
        console.log('Snap.js script loaded, waiting for initialization...')
        // Wait a bit for Snap to initialize
        setTimeout(() => {
          console.log('After 500ms delay - window.snap:', window.snap)
          console.log('After 500ms delay - window.snap?.pay:', window.snap?.pay)
          if (window.snap && typeof window.snap.pay === 'function') {
            snapLoaded = true
            Logger.info('snap.load.success', { hasSnap: true, hasPay: true })
            console.log('✓ Snap.js ready!')
            resolve()
          } else {
            const error = 'Snap.js loaded but window.snap.pay not available'
            Logger.error('snap.load.error', { error, hasSnap: !!window.snap })
            console.error('✗ Snap.js error:', error, { hasSnap: !!window.snap, snapObj: window.snap })
            reject(new Error(error))
          }
        }, 500)
      }

      script.onerror = (error) => {
        Logger.error('snap.script.error', { error, snapUrl })
        reject(new Error('Failed to load Snap.js script'))
      }

      // Append script to document
      document.head.appendChild(script)
      Logger.info('snap.script.appended', { snapUrl })

    } catch (error: any) {
      Logger.error('snap.load.exception', { error: error.message })
      reject(error)
    }
  })

  return snapPromise
}

/**
 * Check if Snap.js is already loaded and ready
 */
export function isSnapReady(): boolean {
  return snapLoaded && !!window.snap && typeof window.snap.pay === 'function'
}

/**
 * Wait for Snap.js to be ready, with timeout
 */
export function waitForSnap(timeoutMs: number = 5000): Promise<void> {
  return new Promise((resolve, reject) => {
    if (isSnapReady()) {
      resolve()
      return
    }

    const startTime = Date.now()
    const checkInterval = setInterval(() => {
      if (isSnapReady()) {
        clearInterval(checkInterval)
        resolve()
      } else if (Date.now() - startTime > timeoutMs) {
        clearInterval(checkInterval)
        reject(new Error(`Snap.js not ready after ${timeoutMs}ms`))
      }
    }, 100)
  })
}
