/**
 * Withholding certificate expiry cron — contractor-payouts (P049, wave 7).
 * Mounted at /api/cron/withholding-expiry-check.
 *
 * Weekly job: checks all contractors for withholding certificates expiring
 * within 30 days, notifies payouts:write members on the tenant.
 *
 * Secured by x-cron-secret header matching env.CRON_SECRET.
 */
import { Hono } from 'hono'
import type { AppEnv } from '../../types'
import {
  createDb,
  createNotification,
  findExpiringWithholdingCertificates,
  getMembersByPermission,
} from '@zync/db/queries'
import { pushOverWebSocket } from '@zync/notifications'
import { timingSafeEqual } from '@zync/auth'

export const withholdingCronRoute = new Hono<AppEnv>()

withholdingCronRoute.get('/withholding-expiry-check', async (c) => {
  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)

  // Find all contractors with certificates expiring in ≤30 days
  const expiring = await findExpiringWithholdingCertificates(db, 30)

  if (expiring.length === 0) {
    return c.json({ checked: 0, notified: 0 })
  }

  // Collect distinct tenant IDs
  const tenantIds = [...new Set(expiring.map((con) => con.tenantId))]

  // Find members that hold payouts:write permission in each tenant.
  let allManagers: { userId: string; tenantId: string }[] = []

  try {
    allManagers = await getMembersByPermission(db, tenantIds, 'payouts:write')
  } catch {
    // Schema not yet migrated — degrade silently, skip notifications
    return c.json({ checked: expiring.length, notified: 0, warning: 'membership_query_failed' })
  }

  let notified = 0

  for (const contractor of expiring) {
    const managers = allManagers.filter((m) => m.tenantId === contractor.tenantId)
    if (managers.length === 0) continue

    const expiryDate = contractor.withholdingCertificateExpiry ?? 'unknown'

    for (const { userId } of managers) {
      await createNotification(
        db,
        {
          tenantId: contractor.tenantId,
          userId,
          type: 'expense_submitted', // Reused for operational alerts per spec
          titleKey: 'notifications.withholding_cert_expiry.title',
          bodyKey: 'notifications.withholding_cert_expiry.body',
          params: {
            contractorName: contractor.name,
            expiryDate,
          },
          entityType: 'contractor',
          entityId: contractor.id,
        },
        {
          // createNotification.pushWS: (userId, tenantId, type) → void
          // pushOverWebSocket: (userId, tenantId, notification, env) → void
          pushWS: (uid, tid, type) =>
            pushOverWebSocket(
              uid,
              tid,
              {
                type,
                titleKey: 'notifications.withholding_cert_expiry.title',
              },
              c.env,
            ),
        },
      )
      notified++
    }
  }

  return c.json({ checked: expiring.length, notified })
})
