import { sql } from "drizzle-orm";
import { db } from "../db/db.controller.js";
import { createLogger } from "../logger/logger.controller.js";

const log = createLogger({
	module: "db",
	subModule: "notifications",
});

/**
 * Creates/updates Postgres notification functions + triggers.
 *
 * Safe to run on every app startup.
 * CREATE OR REPLACE updates the function.
 * DROP TRIGGER IF EXISTS prevents duplicate triggers.
 */
export async function setupDbNotifications() {
	log.info({}, "Setting up DB notifications");

	await setupLogsNotifications();
	await setupDockScansNotifications();
	await setupProdAuditNotifications();

	log.info({}, "DB notifications setup complete");
}

/**
 * Logs notification setup.
 *
 * Flow:
 * 1. app inserts into logs table
 * 2. trigger runs after insert
 * 3. Postgres sends NOTIFY logs_inserted with the new log id
 * 4. Node listener receives id and fetches/emits full row
 */
async function setupLogsNotifications() {
	await db.execute(sql`
		CREATE OR REPLACE FUNCTION notify_logs_inserted()
		RETURNS trigger AS $$
		BEGIN
			PERFORM pg_notify(
				'logs_inserted',
				json_build_object(
					'table', TG_TABLE_NAME,
					'action', TG_OP,
					'id', NEW.id
				)::text
			);

			RETURN NEW;
		END;
		$$ LANGUAGE plpgsql;
	`);

	await db.execute(sql`
		DROP TRIGGER IF EXISTS logs_inserted_notify_trigger ON logs;
	`);

	await db.execute(sql`
		CREATE TRIGGER logs_inserted_notify_trigger
		AFTER INSERT ON logs
		FOR EACH ROW
		EXECUTE FUNCTION notify_logs_inserted();
	`);

	log.info({}, "Logs DB notification trigger ready");
}

async function setupDockScansNotifications() {
	await db.execute(sql`
		CREATE OR REPLACE FUNCTION notify_dock_scan_inserted()
		RETURNS trigger AS $$
		BEGIN
			PERFORM pg_notify(
				'dock_scan_inserted',
				json_build_object(
					'table', TG_TABLE_NAME,
					'action', TG_OP,
					'id', NEW.id
				)::text
			);

			RETURN NEW;
		END;
		$$ LANGUAGE plpgsql;
	`);

	await db.execute(sql`
		DROP TRIGGER IF EXISTS dock_scan_inserted_notify_trigger ON dock_door_scans;
	`);

	await db.execute(sql`
		CREATE TRIGGER dock_scan_inserted_notify_trigger
		AFTER INSERT ON dock_door_scans
		FOR EACH ROW
		EXECUTE FUNCTION notify_dock_scan_inserted();
	`);

	log.info({}, "Dock scan DB notification trigger ready");
}

async function setupProdAuditNotifications() {
	await db.execute(sql`
		CREATE OR REPLACE FUNCTION notify_auditLog_inserted()
		RETURNS trigger AS $$
		BEGIN
			PERFORM pg_notify(
				'auditLog_inserted',
				json_build_object(
					'table', TG_TABLE_NAME,
					'action', TG_OP,
					'id', NEW.id
				)::text
			);

			RETURN NEW;
		END;
		$$ LANGUAGE plpgsql;
	`);

	await db.execute(sql`
		DROP TRIGGER IF EXISTS auditLog_inserted_notify_trigger ON prod_audit_log;
	`);

	await db.execute(sql`
		CREATE TRIGGER auditLog_inserted_notify_trigger
		AFTER INSERT ON prod_audit_log
		FOR EACH ROW
		EXECUTE FUNCTION notify_auditLog_inserted();
	`);

	log.info({}, "Audit Log DB notification trigger ready");
}
