/**
 * Inbound communications queue consumer — system-communications-notifications (Task 15).
 *
 * Processes messages from the `comms.inbound` Cloudflare Queue.
 * Each message contains { tenantId, source, message: InboundMessage, receivedAt }.
 *
 * Routing logic:
 *   - autoCreateTickets=true → createSupportTicket (crm-support-center seam)
 *   - aiAssistantEnabled=true → dispatchToAiAssistant (ai-assistant seam)
 *   Both can fire for one message.
 *
 * Idempotency: dedupe by provider message id stored in KV.
 * Ack on success; throw to trigger Queue retry/backoff.
 */
import { createDb, routeInboundMessage, getTenantById } from '@zync/db/queries'
import type { InboundMessage, TenantId } from '@zync/types'
import type { Env } from '@zync/types'
import { dispatchToAiAssistant } from '../ai/dispatch-to-assistant'
import { tryCommsExpenseIntake } from '../intake/comms-expense'
import { bindCreateSupportTicket } from '../services/create-support-ticket'
import type { InboundTicketChannel } from '../services/create-support-ticket'
import { handleInboundForTasks } from '../queue/tasks-inbound'

interface InboundQueueMessage {
  type: 'comms.inbound'
  source: InboundTicketChannel
  tenantId: string
  message: InboundMessage
  receivedAt: string
}

/**
 * Get the provider-specific message ID for deduplication.
 * Falls back to a hash of chatId+text+receivedAt.
 */
function getProviderMessageId(msg: InboundQueueMessage): string {
  const metadata = msg.message.metadata
  const id =
    (metadata['waMessageId'] as string | undefined) ??
    (metadata['messageId'] as string | undefined) ??
    (metadata['ts'] as string | undefined)
  if (id) return `${msg.source}:${id}`
  // Fallback: composite key
  return `${msg.source}:${msg.message.chatId}:${msg.receivedAt}`
}

export async function handleCommsInboundBatch(
  batch: MessageBatch<unknown>,
  env: Env,
): Promise<void> {
  for (const queueMsg of batch.messages) {
    const msg = queueMsg.body as InboundQueueMessage

    if (msg.type !== 'comms.inbound') {
      queueMsg.ack()
      continue
    }

    try {
      // Idempotency check via KV
      const dedupeKey = `comms:inbound:seen:${getProviderMessageId(msg)}`
      const alreadyProcessed = await env.KV.get(dedupeKey)
      if (alreadyProcessed) {
        queueMsg.ack()
        continue
      }

      // Load tenant comms config from DB
      const db = createDb(env)
      const tenantConfig = await loadTenantCommsConfig(db, msg.tenantId)

      let intakeHandled = false
      if (msg.source === 'whatsapp' || msg.source === 'telegram') {
        intakeHandled = await tryCommsExpenseIntake(env, msg.tenantId, msg.source, msg.message)
      }
      if (intakeHandled) {
        await env.KV.put(dedupeKey, '1', { expirationTtl: 604_800 })
        queueMsg.ack()
        continue
      }

      await handleInboundForTasks(msg, db)

      // Route the message
      await routeInboundMessage(msg.message, tenantConfig, {
        createSupportTicket: bindCreateSupportTicket(env, msg.tenantId, msg.source),
        dispatchToAiAssistant: (inboundMsg) =>
          dispatchToAiAssistant(env, inboundMsg, tenantConfig, msg.tenantId),
      })

      // Mark as processed (TTL: 7 days for deduplication window)
      await env.KV.put(dedupeKey, '1', { expirationTtl: 604_800 })

      queueMsg.ack()
    } catch (err) {
      // Throw causes the Queue to retry with backoff
      // Do NOT ack — let the Queue handle retry
      console.error('[comms-inbound] Failed to process message:', err)
      queueMsg.retry()
    }
  }
}

/**
 * Load tenant communications config from tenant_settings.
 * Defaults to safe values (no auto-create, no AI) if not configured.
 *
 * NOTE: auto_create_tickets and ai_assistant_enabled columns are added to
 * tenant_settings by this spec's migration. Until the migration is applied
 * (or if the columns don't exist yet), we degrade gracefully to false.
 */
async function loadTenantCommsConfig(
  db: ReturnType<typeof createDb>,
  tenantId: string,
): Promise<{ autoCreateTickets: boolean; aiAssistantEnabled: boolean; telegramAiChatId: string | null }> {
  try {
    const tenant = await getTenantById(db, tenantId as TenantId)
    if (!tenant) return { autoCreateTickets: false, aiAssistantEnabled: false, telegramAiChatId: null }

    // Try reading from the tenant settings JSONB field (bridge until typed columns)
    const settings = tenant.settings as {
      autoCreateTickets?: boolean
      aiAssistantEnabled?: boolean
      telegramAiChatId?: string | null
    } | null

    return {
      autoCreateTickets: settings?.autoCreateTickets ?? false,
      aiAssistantEnabled: settings?.aiAssistantEnabled ?? false,
      telegramAiChatId: settings?.telegramAiChatId ?? null,
    }
  } catch {
    return { autoCreateTickets: false, aiAssistantEnabled: false, telegramAiChatId: null }
  }
}
