import { query } from '../db/client.js'

export type AdminNotificationRow = {
  id: number
  notification_type: string
  priority: string
  entity_type: string
  entity_id: number
  dedupe_key: string
  title: string
  body: string
  action_path: string
  payload_json: string | Record<string, unknown>
  visible: boolean
  sound_enabled: boolean
  reminder_count: number
  last_reminded_at: string | null
  status: string
  resolved_at: string | null
  resolution_reason: string
  created_at: string
  updated_at: string
}

export async function createAdminNotification(input: {
  notificationType: string
  priority: string
  entityType: string
  entityId: number
  dedupeKey: string
  title: string
  body: string
  actionPath: string
  payloadJson?: string
  visible?: boolean
  soundEnabled?: boolean
  now: string
}): Promise<AdminNotificationRow | null> {
  const result = await query<AdminNotificationRow>(
    `
      INSERT INTO admin_notifications (
        notification_type, priority, entity_type, entity_id, dedupe_key,
        title, body, action_path, payload_json, visible, sound_enabled, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb, $10, $11, $12, $12)
      ON CONFLICT (dedupe_key) DO NOTHING
      RETURNING *
    `,
    [
      input.notificationType,
      input.priority,
      input.entityType,
      input.entityId,
      input.dedupeKey,
      input.title,
      input.body,
      input.actionPath,
      input.payloadJson || '{}',
      input.visible !== false,
      input.soundEnabled !== false,
      input.now,
    ],
  )
  return result.rows[0] || null
}

export async function getPendingAdminNotificationByDedupeKey(
  dedupeKey: string,
): Promise<AdminNotificationRow | null> {
  const result = await query<AdminNotificationRow>(
    `SELECT * FROM admin_notifications WHERE dedupe_key = $1 AND status = 'pending' LIMIT 1`,
    [dedupeKey],
  )
  return result.rows[0] || null
}

export async function bumpAdminNotificationReminder(input: {
  dedupeKey: string
  notificationType: string
  title: string
  visible: boolean
  soundEnabled: boolean
  now: string
}): Promise<AdminNotificationRow | null> {
  const result = await query<AdminNotificationRow>(
    `
      UPDATE admin_notifications
      SET
        notification_type = $1,
        title = $2,
        priority = 'high',
        visible = visible OR $3,
        sound_enabled = $4,
        reminder_count = reminder_count + 1,
        last_reminded_at = $5,
        updated_at = $5
      WHERE dedupe_key = $6
        AND status = 'pending'
        AND reminder_count < 3
        AND (
          last_reminded_at IS NULL
          OR last_reminded_at <= $5::timestamptz - INTERVAL '30 minutes'
        )
      RETURNING *
    `,
    [
      input.notificationType,
      input.title,
      input.visible,
      input.soundEnabled,
      input.now,
      input.dedupeKey,
    ],
  )
  return result.rows[0] || null
}

export async function resolveAdminNotificationsByEntity(input: {
  entityType: string
  entityId: number
  reason: string
  now: string
}): Promise<void> {
  await query(
    `
      UPDATE admin_notifications
      SET status = 'resolved', resolved_at = $1, resolution_reason = $2, updated_at = $1
      WHERE entity_type = $3 AND entity_id = $4 AND status = 'pending'
    `,
    [input.now, input.reason, input.entityType, input.entityId],
  )
}

export async function listPendingAdminNotifications(
  limit: number,
): Promise<AdminNotificationRow[]> {
  const result = await query<AdminNotificationRow>(
    `
      SELECT *
      FROM admin_notifications
      WHERE status = 'pending' AND visible = TRUE
      ORDER BY
        CASE priority WHEN 'urgent' THEN 3 WHEN 'high' THEN 2 ELSE 1 END DESC,
        updated_at DESC,
        id DESC
      LIMIT $1
    `,
    [limit],
  )
  return result.rows
}

export async function countPendingAdminNotifications(): Promise<number> {
  const result = await query<{ total: number }>(
    `SELECT COUNT(*)::int AS total FROM admin_notifications WHERE status = 'pending' AND visible = TRUE`,
  )
  return Number(result.rows[0]?.total || 0)
}
