/**
 * Contract signing reminders cron — multi-signatory-coordination (wave-12).
 *
 * POST /api/cron/contract-signing-reminders
 *
 * Guarded by CRON_SECRET (timing-safe comparison via @zync/auth#timingSafeEqual).
 * Schedule: `0 9 * * *` (daily 09:00 UTC = 10:00 Israel in winter, 12:00 in summer — UTC is authoritative).
 *
 * Algorithm:
 *   1. SELECT signatories due for a reminder:
 *      - Contract status IN ('sent', 'viewed')
 *      - Signatory not yet signed and not declined
 *      - Last reminder null OR > 7 days ago
 *      - Currently their turn (sequential order check — the turn-gate subquery)
 *   2. For each due signatory: send invitation email, bump reminder_sent_at + reminder_count,
 *      append contract_audit_log row with actorType='system'.
 *   3. Per-row errors are caught so one failure does not abort the entire run.
 *
 * Note: the cron cadence (7 days) is independent of the manual 24h gate in the reminder endpoint;
 * both share the reminder_sent_at column.
 */
import { Hono } from 'hono'
import { sql } from '@zync/db'
import { timingSafeEqual } from '@zync/auth'
import { createDb, markSignatoryReminderSent, appendContractAuditLog } from '@zync/db/queries'
import { sendEmail } from '@zync/notifications'
import type { AppEnv } from '../../types'

export const contractSigningRemindersCron = new Hono<AppEnv>()

contractSigningRemindersCron.post('/', async (c) => {
  // ── CRON_SECRET guard ──────────────────────────────────────────────────────
  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: 'Unauthorized' }, 401)
  }

  const db = createDb(c.env)

  // ── Query due signatories ──────────────────────────────────────────────────
  // Select signatories due for an auto-reminder:
  //   - Contract status is 'sent' or 'viewed'
  //   - Signatory not yet signed and not declined
  //   - Reminder not sent recently (null or > 7 days ago)
  //   - Currently their turn in sequential order (turn-gate subquery)
  //
  // NOTE: contract status values in this codebase are lowercase: 'sent', 'viewed'
  const dueRows = await db.execute<{
    id: string
    email: string
    name: string | null
    token: string
    contract_id: string
    tenant_id: string
    contract_title: string
  }>(sql`
    SELECT
      cs.id,
      cs.email,
      cs.name,
      cs.token,
      cs.contract_id,
      cs.tenant_id,
      c.title AS contract_title
    FROM contract_signatories cs
    JOIN contracts c ON c.id = cs.contract_id
    WHERE c.status IN ('sent', 'viewed')
      AND cs.signed_at IS NULL
      AND cs.declined_at IS NULL
      AND (cs.reminder_sent_at IS NULL OR cs.reminder_sent_at < now() - interval '7 days')
      AND (
        c.id NOT IN (
          SELECT contract_id FROM contract_signatories
          WHERE signed_at IS NULL
            AND declined_at IS NULL
            AND "order" < cs."order"
        )
      )
    LIMIT 500
  `)

  const rows = dueRows as unknown as { id: string; email: string; name: string | null; token: string; contract_id: string; tenant_id: string; contract_title: string }[]

  let sent = 0
  let failed = 0

  for (const row of rows) {
    try {
      // Send reminder email
      await sendEmail(
        {
          to: row.email,
          templateKey: 'invitation',
          locale: 'he-IL',
          vars: {
            subject: `Reminder: Please sign "${row.contract_title}"`,
            title: `Reminder: Please sign "${row.contract_title}"`,
            body: `Hi ${row.name ?? row.email}, this is a reminder to sign the contract "${row.contract_title}".`,
            inviteUrl: `https://app.zync.is/sign/${row.token}`,
            ctaLabel: 'Sign contract',
          },
        },
        c.env,
      )

      // Bump reminder fields + audit
      const now = new Date()
      await db.transaction(async (tx) => {
        await markSignatoryReminderSent(tx, row.tenant_id, row.id, now)

        await appendContractAuditLog(tx, {
          contractId: row.contract_id,
          tenantId: row.tenant_id,
          event: 'reminder_sent',
          actorType: 'system',
          actorId: 'cron:contract-signing-reminders',
          metadata: { signatoryId: row.id, source: 'cron' },
        })
      })

      sent++
    } catch (err) {
      // Log per-row failure and continue — do not abort the entire run
      console.error(`[contract-signing-reminders] failed for signatory ${row.id}:`, err)
      failed++
    }
  }

  return c.json({ sent, failed, total: rows.length, ok: true }, 200)
})
