import { randomUUID } from "node:crypto";
import { getPool } from "../db/pool";
function nowIso() {
    return new Date().toISOString();
}
function cloneNotification(notification) {
    return {
        ...notification,
        payload_json: { ...notification.payload_json }
    };
}
function mapNotification(row) {
    return {
        id: row.id,
        transaction_id: row.transaction_id,
        device_id: row.device_id || null,
        delivery_channel: "mqtt",
        payload_type: "payment_success",
        delivery_status: row.delivery_status,
        retry_count: row.retry_count,
        ack_status: row.ack_status,
        event_id: row.event_id,
        reason: row.reason || undefined,
        payload_json: row.payload_json || {},
        created_at: row.created_at,
        updated_at: row.updated_at,
        sent_at: row.sent_at || undefined,
        ack_at: row.ack_at || undefined,
        next_retry_at: row.next_retry_at || undefined
    };
}
export async function createNotification(payload) {
    const now = nowIso();
    const insert = await getPool().query(`INSERT INTO notifications (
      id,
      transaction_id,
      device_id,
      delivery_status,
      retry_count,
      ack_status,
      event_id,
      reason,
      payload_json,
      created_at,
      updated_at
    ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
    ON CONFLICT (transaction_id, event_id) DO UPDATE
    SET updated_at = EXCLUDED.updated_at
    RETURNING *`, [
        randomUUID(),
        payload.transaction_id,
        payload.device_id,
        payload.delivery_status,
        0,
        payload.ack_status || "not_needed",
        payload.event_id,
        payload.reason || null,
        payload.payload_json || {},
        now,
        now
    ]);
    if (insert.rowCount && insert.rowCount > 0) {
        return mapNotification(insert.rows[0]);
    }
    const { rows } = await getPool().query("SELECT * FROM notifications WHERE transaction_id = $1 AND event_id = $2", [payload.transaction_id, payload.event_id]);
    return mapNotification(rows[0]);
}
export async function getNotificationById(notificationId) {
    const { rows } = await getPool().query("SELECT * FROM notifications WHERE id = $1", [notificationId]);
    return rows[0] ? cloneNotification(mapNotification(rows[0])) : null;
}
export async function updateNotification(notificationId, patch) {
    const existing = await getNotificationById(notificationId);
    if (!existing) {
        throw new Error("NOTIFICATION_NOT_FOUND");
    }
    const next = {
        ...existing,
        ...patch,
        id: existing.id,
        transaction_id: existing.transaction_id,
        device_id: existing.device_id,
        delivery_channel: existing.delivery_channel,
        payload_type: existing.payload_type,
        event_id: existing.event_id,
        payload_json: existing.payload_json,
        created_at: existing.created_at,
        updated_at: nowIso()
    };
    const { rows } = await getPool().query(`UPDATE notifications
     SET delivery_status = $2,
         retry_count = $3,
         ack_status = $4,
         device_id = COALESCE($5, device_id),
         reason = $6,
         sent_at = $7,
         ack_at = $8,
         next_retry_at = $9,
         updated_at = $10
     WHERE id = $1
     RETURNING *`, [
        notificationId,
        next.delivery_status,
        next.retry_count,
        next.ack_status,
        next.device_id ?? null,
        next.reason || null,
        next.sent_at || null,
        next.ack_at || null,
        next.next_retry_at || null,
        next.updated_at
    ]);
    return cloneNotification(mapNotification(rows[0]));
}
export async function getNotificationByTransactionId(transactionId) {
    const { rows } = await getPool().query(`SELECT * FROM notifications
     WHERE transaction_id = $1
     ORDER BY created_at DESC
     LIMIT 1`, [transactionId]);
    return rows[0] ? mapNotification(rows[0]) : null;
}
export async function getNotificationByTransactionAndEvent(transactionId, eventId) {
    const { rows } = await getPool().query("SELECT * FROM notifications WHERE transaction_id = $1 AND event_id = $2", [transactionId, eventId]);
    return rows[0] ? mapNotification(rows[0]) : null;
}
export async function listNotificationsByDevice(deviceId) {
    const { rows } = await getPool().query("SELECT * FROM notifications WHERE device_id = $1 ORDER BY created_at DESC", [deviceId]);
    return rows.map(mapNotification);
}
export async function listNotifications(filter) {
    const filters = [];
    const params = [];
    if (filter?.transaction_id) {
        params.push(filter.transaction_id);
        filters.push(`transaction_id = $${params.length}`);
    }
    if (filter?.device_id) {
        params.push(filter.device_id);
        filters.push(`device_id = $${params.length}`);
    }
    if (filter?.delivery_status) {
        params.push(filter.delivery_status);
        filters.push(`delivery_status = $${params.length}`);
    }
    const where = filters.length ? `WHERE ${filters.join(" AND ")}` : "";
    const { rows } = await getPool().query(`SELECT * FROM notifications ${where} ORDER BY created_at DESC`, params);
    return rows.map(mapNotification);
}
export function toNotificationPayload(notification) {
    return cloneNotification(notification);
}
