/**
 * SLA breach detection cron — ticket-sla-escalation (P063).
 *
 * POST /api/cron/ticket-sla-check
 *
 * Guarded by CRON_SECRET (timing-safe comparison via @zync/auth#timingSafeEqual).
 * Runs every 15 minutes (wrangler.toml cron trigger: every-15-min).
 *
 * Algorithm:
 *  1. UPDATE tickets SET sla_breached = true WHERE due_at < now() AND not resolved/closed
 *     → returns newly-breached ticket refs (id, tenant_id, assignee_id, priority)
 *  2. For each newly-breached ticket, look up the matching sla_policies row.
 *  3. Per policy:
 *     - notify_in_app: emit in-app notification to assignee (if set)
 *     - notify_email + escalation_email: send escalation email
 *
 * Scheduled: every-15-min (Cloudflare Cron Trigger, name: ticket-sla-check)
 */
import { Hono } from 'hono'
import { timingSafeEqual } from '@zync/auth'
import {
  createDb,
  createNotification,
  findAndMarkBreachedTickets,
  getSlaPolicyByPriority,
  getOwnerAdminUserIds,
} from '@zync/db/queries'
import { sendEmail } from '@zync/notifications'
import type { AppEnv } from '../../types'

export const ticketSlaCheckCron = new Hono<AppEnv>()

ticketSlaCheckCron.post('/', async (c) => {
  // Timing-safe secret check — never use ===
  const secret = c.req.header('x-cron-secret') ?? ''
  const expected = c.env.CRON_SECRET
  if (!expected || expected.length < 16) {
    return c.json({ error: 'Server misconfigured' }, 500)
  }

  if (!timingSafeEqual(secret, expected)) {
    return c.json({ error: 'Forbidden' }, 403)
  }

  const db = createDb(c.env)

  // Step 1: Find and atomically mark breached tickets
  const breachedTickets = await findAndMarkBreachedTickets(db)

  if (breachedTickets.length === 0) {
    return c.json({ checked: true, breached: 0 }, 200)
  }

  let notified = 0
  let emailsSent = 0

  // Step 2+3: Dispatch notifications per ticket
  for (const ticket of breachedTickets) {
    try {
      const policy = await getSlaPolicyByPriority(db, ticket.tenant_id, ticket.priority)
      if (!policy) continue

      if (policy.notify_in_app) {
        const recipients = new Set<string>()
        if (ticket.assignee_id) recipients.add(ticket.assignee_id)
        for (const userId of await getOwnerAdminUserIds(db, ticket.tenant_id)) {
          recipients.add(userId)
        }
        for (const userId of recipients) {
          await createNotification(db, {
            tenantId: ticket.tenant_id,
            userId,
            type: 'ticket_escalated',
            titleKey: 'notification.ticket_escalated.title',
            bodyKey: 'notification.ticket_escalated.body',
            params: {
              ticketNumber: ticket.id,
              priority: ticket.priority,
            },
            entityType: 'ticket',
            entityId: ticket.id,
          })
          notified++
        }
      }

      // Escalation email
      if (policy.notify_email && policy.escalation_email) {
        try {
          await sendEmail(
            {
              to: policy.escalation_email,
              templateKey: 'ticket_sla_breach',
              vars: {
                ticketId: ticket.id,
                priority: ticket.priority,
                tenantId: ticket.tenant_id,
              },
              locale: 'he-IL',
            },
            c.env,
          )
          emailsSent++
        } catch {
          // Log but do not abort — one failed email must not stop other tickets
        }
      }
    } catch {
      // Per-ticket error isolation: log and continue
    }
  }

  return c.json(
    { checked: true, breached: breachedTickets.length, notified, emails_sent: emailsSent },
    200,
  )
})
