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

declare global {
  interface Window {
    MidtransNew3ds?: {
      getCardToken: (
        params: {
          clientKey: string
          card_number: string
          card_exp_month: string
          card_exp_year: string
          card_cvv: string
        },
        callback: (response: { status_code: string; status_message: string; token_id?: string; validation_messages?: string[] }) => void
      ) => void
      authenticate: (redirectUrl: string) => void
    }
  }
}

/**
 * Ensure Midtrans 3DS script is loaded with correct attributes.
 */
export async function ensureMidtrans3ds(): Promise<void> {
  Logger.info('3ds.ensure.start')
  if (window.MidtransNew3ds) {
    Logger.info('3ds.ensure.present')
    return
  }
  await new Promise<void>((resolve, reject) => {
    const existing = document.getElementById('midtrans-script') as HTMLScriptElement | null
    if (existing) {
      Logger.debug('3ds.script.existing')
      if (window.MidtransNew3ds) return resolve()
      existing.addEventListener('load', () => resolve())
      existing.addEventListener('error', () => {
        Logger.error('3ds.script.error', { stage: 'existing' })
        reject(new Error('Midtrans 3DS script failed to load'))
      })
      return
    }
    const script = document.createElement('script')
    script.id = 'midtrans-script'
    script.type = 'text/javascript'
    script.src = 'https://api.midtrans.com/v2/assets/js/midtrans-new-3ds.min.js'
    script.setAttribute('data-environment', Env.MIDTRANS_ENV)
    script.setAttribute('data-client-key', Env.MIDTRANS_CLIENT_KEY)
    script.async = true
    script.onload = () => { Logger.info('3ds.script.loaded'); resolve() }
    script.onerror = () => { Logger.error('3ds.script.error', { stage: 'inject' }); reject(new Error('Midtrans 3DS script failed to load')) }
    Logger.info('3ds.script.inject', { env: Env.MIDTRANS_ENV, hasClientKey: !!Env.MIDTRANS_CLIENT_KEY })
    document.body.appendChild(script)
  })
  // Basic guard: require client key for tokenization
  if (!Env.MIDTRANS_CLIENT_KEY) {
    Logger.error('3ds.clientKey.missing')
    throw new Error('Midtrans client key not configured')
  }
}

export interface CardTokenParams {
  card_number: string
  card_exp_month: string
  card_exp_year: string
  card_cvv: string
}

export async function getCardToken(params: CardTokenParams): Promise<string> {
  await ensureMidtrans3ds()
  return new Promise<string>((resolve, reject) => {
    const sdk = window.MidtransNew3ds
    if (!sdk) {
      Logger.error('3ds.sdk.missing')
      return reject(new Error('MidtransNew3ds not available'))
    }
    Logger.info('3ds.token.start')
    // Safety timeout to prevent indefinite loading when SDK doesn’t callback
    const timeout = setTimeout(() => {
      Logger.error('3ds.token.timeout')
      reject(new Error('Tokenisasi kartu timeout. Periksa koneksi atau konfigurasi kunci klien.'))
    }, 15000)
    sdk.getCardToken(
      {
        clientKey: Env.MIDTRANS_CLIENT_KEY,
        card_number: params.card_number,
        card_exp_month: params.card_exp_month,
        card_exp_year: params.card_exp_year,
        card_cvv: params.card_cvv,
      },
      (response) => {
        clearTimeout(timeout)
        if (response && response.token_id) {
          Logger.info('3ds.token.success')
          return resolve(response.token_id)
        }
        Logger.error('3ds.token.fail', { message: response?.status_message, validations: response?.validation_messages })
        reject(new Error(response?.status_message || 'Failed to tokenize card'))
      }
    )
  })
}

export function authenticate3ds(redirectUrl: string) {
  if (!redirectUrl) return
  if (!window.MidtransNew3ds) return
  window.MidtransNew3ds.authenticate(redirectUrl)
}