import type { CommerceEvent, WooCart } from '@/types'
import { getCurrentLocale } from '@/utils/locale'

const FLUSH_INTERVAL_MS = 10_000
const MAX_BATCH_SIZE = 20

let queue: CommerceEvent[] = []
let flushTimer: number | null = null
let listenersBound = false

function getApiBase(): string {
  const base = window.boostbot_config?.rest_url || window.boostbot_config?.api_url || '/wp-json/boostbot/v1'
  return base.replace(/\/$/, '')
}

function getEndpointUrl(): string {
  return `${getApiBase()}/commerce-events`
}

function parseAmount(value: unknown): number | null {
  if (typeof value === 'number' && Number.isFinite(value)) {
    return value
  }

  if (typeof value === 'string') {
    const trimmed = value.trim()
    if (!trimmed) {
      return null
    }

    const normalized = trimmed.replace(/,/g, '')
    const parsed = Number(normalized)
    return Number.isFinite(parsed) ? parsed : null
  }

  return null
}

function inferLanguage(preferred?: string | null): string {
  if (preferred && preferred.trim()) {
    return preferred.trim().toLowerCase()
  }

  const locale = window.boostbot_config?.locale || window.boostbot_config?.primary_language || getCurrentLocale() || 'he'
  return String(locale).split(/[-_]/)[0]?.toLowerCase() || 'he'
}

function inferCurrencyCode(event: Partial<CommerceEvent>): string | undefined {
  if (event.currency_code) {
    return event.currency_code
  }

  const productCurrency = window.boostbot_config?.woocommerce?.product?.currency_code
  if (productCurrency) {
    return productCurrency
  }

  const configCurrency = window.boostbot_config?.woocommerce?.currency_code
  if (configCurrency) {
    return configCurrency
  }

  const language = inferLanguage(event.language)
  if (language === 'he') {
    return 'ILS'
  }

  if (language === 'en') {
    return 'USD'
  }

  return undefined
}

function normalizeEvent(event: CommerceEvent): CommerceEvent {
  return {
    ...event,
    timestamp: event.timestamp || new Date().toISOString(),
    language: inferLanguage(event.language),
    currency_code: inferCurrencyCode(event),
    source_page: event.source_page || window.location.href,
  }
}

function scheduleFlush(): void {
  if (flushTimer !== null) {
    return
  }

  flushTimer = window.setTimeout(() => {
    flushTimer = null
    void flushCommerceEvents()
  }, FLUSH_INTERVAL_MS)
}

function bindLifecycleListeners(): void {
  if (listenersBound || typeof window === 'undefined') {
    return
  }

  listenersBound = true

  const flushWithBeacon = () => {
    void flushCommerceEvents({ transport: 'beacon' })
  }

  window.addEventListener('pagehide', flushWithBeacon)
  window.addEventListener('beforeunload', flushWithBeacon)
  document.addEventListener('visibilitychange', () => {
    if (document.visibilityState === 'hidden') {
      flushWithBeacon()
    }
  })
}

async function postBatch(batch: CommerceEvent[], options?: { transport?: 'fetch' | 'beacon' }): Promise<boolean> {
  if (batch.length === 0) {
    return true
  }

  const payload = JSON.stringify({ events: batch })

  if (options?.transport === 'beacon' && typeof navigator.sendBeacon === 'function') {
    const blob = new Blob([payload], { type: 'application/json' })
    return navigator.sendBeacon(getEndpointUrl(), blob)
  }

  try {
    const response = await fetch(getEndpointUrl(), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: payload,
      keepalive: options?.transport === 'beacon',
    })

    return response.ok
  } catch {
    return false
  }
}

export function getCartTelemetryFields(cart?: WooCart | null): Pick<CommerceEvent, 'currency_code' | 'cart_item_count' | 'cart_subtotal' | 'cart_total' | 'discount_total' | 'order_value'> {
  return {
    currency_code: cart?.currency_code || undefined,
    cart_item_count: typeof cart?.count === 'number' ? cart.count : null,
    cart_subtotal: parseAmount(cart?.subtotal_amount),
    cart_total: parseAmount(cart?.total_amount),
    discount_total: parseAmount(cart?.discount_total),
    order_value: parseAmount(cart?.total_amount),
  }
}

export function trackCommerceEvent(event: CommerceEvent): void {
  if (typeof window === 'undefined') {
    return
  }

  bindLifecycleListeners()
  queue.push(normalizeEvent(event))

  if (queue.length >= MAX_BATCH_SIZE) {
    void flushCommerceEvents()
    return
  }

  scheduleFlush()
}

export async function flushCommerceEvents(options?: { transport?: 'fetch' | 'beacon' }): Promise<void> {
  if (typeof window === 'undefined' || queue.length === 0) {
    return
  }

  if (flushTimer !== null) {
    window.clearTimeout(flushTimer)
    flushTimer = null
  }

  const batch = queue.splice(0, queue.length)
  const posted = await postBatch(batch, options)

  if (!posted) {
    queue = [...batch, ...queue].slice(0, MAX_BATCH_SIZE * 10)
    if (!options || options.transport !== 'beacon') {
      scheduleFlush()
    }
  }
}
