/**
 * Per-invoice reminder routes — invoice-payment-reminders (wave-13).
 * Mounted at /api/invoices (sub-routes).
 *
 * POST /:id/reminders/send     → manual reminder send
 * PATCH /:id/reminders         → enable/disable reminders for an invoice
 */
import { Hono } from 'hono'
import { z } from 'zod'
import type { AppEnv } from '../../types'
import { authMiddleware } from '../../middleware/auth'
import { requirePermission } from '../../middleware/guards'
import {
  createDb,
  getInvoiceWithLines,
  disableInvoiceReminders,
  setInvoiceReminderState,
  computeNextReminder,
  getTenantReminderSettings,
  parseReminderSchedule,
  logAuditEvent,
} from '@zync/db/queries'
import { sendInvoiceReminder } from '../../services/invoice-reminder-send'
import type { ReminderDueInvoice } from '@zync/db/queries'

// ── Zod schemas ───────────────────────────────────────────────────────────────

const patchReminderSchema = z.object({
  disabled: z.boolean(),
})

// ── Router ─────────────────────────────────────────────────────────────────────

export const invoiceRemindersRoutes = new Hono<AppEnv>()

invoiceRemindersRoutes.use('*', authMiddleware)

// POST /api/invoices/:id/reminders/send
invoiceRemindersRoutes.post(
  '/:id/reminders/send',
  requirePermission('invoices:write'),
  async (c) => {
    const session = c.get('session')
    if (!session || session.type !== 'user' || !session.tid) {
      return c.json({ error: 'Unauthorized' }, 401)
    }

    const invoiceId = c.req.param('id')
    const db = createDb(c.env)

    const invoice = await getInvoiceWithLines(db, session.tid, invoiceId)
    if (!invoice) {
      return c.json({ error: 'Invoice not found' }, 404)
    }

    const payableStatuses = ['SENT', 'APPROVED', 'TAX_ISSUED', 'PARTIALLY_PAID']
    if (!payableStatuses.includes(invoice.status)) {
      return c.json({ error: 'Invoice is not in a payable state' }, 422)
    }

    // Build a ReminderDueInvoice-shaped object for the send service
    // schedule and dueDate are derived inside sendInvoiceReminder from tenantSettings
    const currentOffset = (invoice as { nextReminderOffset?: number | null }).nextReminderOffset ?? null

    const reminderInvoice: ReminderDueInvoice = {
      id: invoice.id,
      tenantId: session.tid,
      customerId: invoice.customerId ?? null,
      dueDate: invoice.dueDate ?? null,
      status: invoice.status,
      invoiceNumber: invoice.invoiceNumber ?? null,
      proformaNumber: invoice.proformaNumber ?? null,
      total: invoice.total,
      currency: invoice.currency,
      reminderCount: (invoice as { reminderCount?: number }).reminderCount ?? 0,
      nextReminderOffset: currentOffset,
      paymentLinkSentAt: (invoice as { paymentLinkSentAt?: Date | null }).paymentLinkSentAt ?? null,
    }

    const result = await sendInvoiceReminder(db, c.env, reminderInvoice, { manualSend: true })

    await logAuditEvent(c, {
      tenantId: session.tid,
      userId: session.sub,
      entityType: 'invoice',
      entityId: invoiceId,
      eventType: 'reminder.sent',
      metadata: { manual: true, recipient: result.recipient ?? null },
    })

    if (!result.sent) {
      return c.json({ sent: false, skipped: result.skipped }, 200)
    }

    return c.json({ sent: true, recipient: result.recipient }, 200)
  },
)

// PATCH /api/invoices/:id/reminders
invoiceRemindersRoutes.patch(
  '/:id/reminders',
  requirePermission('invoices:write'),
  async (c) => {
    const session = c.get('session')
    if (!session || session.type !== 'user' || !session.tid) {
      return c.json({ error: 'Unauthorized' }, 401)
    }

    const invoiceId = c.req.param('id')
    const body = await c.req.json().catch(() => null)
    const parsed = patchReminderSchema.safeParse(body)
    if (!parsed.success) {
      return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)
    }

    const db = createDb(c.env)

    const invoice = await getInvoiceWithLines(db, session.tid, invoiceId)
    if (!invoice) {
      return c.json({ error: 'Invoice not found' }, 404)
    }

    if (parsed.data.disabled) {
      // Disable: clear next_reminder_at
      await disableInvoiceReminders(db, invoiceId, session.tid, true)
    } else {
      // Re-enable: recompute next_reminder_at from current due_date + settings
      await disableInvoiceReminders(db, invoiceId, session.tid, false)
      const tenantSettings = await getTenantReminderSettings(db, session.tid)
      if (tenantSettings.enabled && invoice.dueDate) {
        const schedule = parseReminderSchedule(tenantSettings.schedule)
        const dueDate = new Date(invoice.dueDate)
        const lastOffset = (invoice as { reminderLastSentAt?: Date | null }).reminderLastSentAt
          ? (invoice as { nextReminderOffset?: number | null }).nextReminderOffset
          : null
        const next = computeNextReminder(dueDate, schedule, lastOffset)
        await setInvoiceReminderState(db, invoiceId, session.tid, next)
      }
    }

    await logAuditEvent(c, {
      tenantId: session.tid,
      userId: session.sub,
      entityType: 'invoice',
      entityId: invoiceId,
      eventType: 'reminder.updated',
      metadata: { disabled: parsed.data.disabled },
    })

    return c.json({ ok: true, disabled: parsed.data.disabled }, 200)
  },
)
