import { randomUUID } from "node:crypto";
import { getPool, withClient } from "../db/pool";
function nowIso() {
    return new Date().toISOString();
}
function mapBinding(row) {
    return {
        id: row.id,
        device_id: row.device_id,
        merchant_id: row.merchant_id,
        outlet_id: row.outlet_id,
        terminal_id: row.terminal_id,
        active_flag: row.active_flag,
        bound_at: row.bound_at,
        unbound_at: row.unbound_at || undefined
    };
}
export async function getActiveBindingByDevice(deviceId) {
    const { rows } = await getPool().query(`SELECT * FROM device_bindings
     WHERE device_id = $1 AND active_flag = TRUE
     ORDER BY bound_at DESC
     LIMIT 1`, [deviceId]);
    return rows[0] ? mapBinding(rows[0]) : null;
}
export async function getActiveBindingByTerminal(terminalId) {
    const { rows } = await getPool().query(`SELECT * FROM device_bindings
     WHERE terminal_id = $1 AND active_flag = TRUE
     ORDER BY bound_at DESC
     LIMIT 1`, [terminalId]);
    return rows[0] ? mapBinding(rows[0]) : null;
}
export async function getBindingsByDeviceId(deviceId) {
    const { rows } = await getPool().query(`SELECT * FROM device_bindings
     WHERE device_id = $1
     ORDER BY bound_at DESC`, [deviceId]);
    return rows.map(mapBinding);
}
export async function bindDevice(payload) {
    const now = nowIso();
    const result = await withClient(async (client) => {
        const existing = await client.query(`SELECT * FROM device_bindings
       WHERE device_id = $1 AND active_flag = TRUE
       ORDER BY bound_at DESC
       LIMIT 1`, [payload.device_id]);
        const same = existing.rows[0]
            ? mapBinding(existing.rows[0])
            : null;
        if (same &&
            same.merchant_id === payload.merchant_id &&
            same.outlet_id === payload.outlet_id &&
            same.terminal_id === payload.terminal_id) {
            return same;
        }
        await client.query("BEGIN");
        try {
            if (existing.rows[0]) {
                await client.query(`UPDATE device_bindings
             SET active_flag = FALSE, unbound_at = $2
           WHERE id = $1`, [same.id, now]);
            }
            const id = randomUUID();
            const inserted = await client.query(`INSERT INTO device_bindings (
            id,
            device_id,
            merchant_id,
            outlet_id,
            terminal_id,
            active_flag,
            bound_at
         ) VALUES ($1,$2,$3,$4,$5,TRUE,$6)
         RETURNING *`, [id, payload.device_id, payload.merchant_id, payload.outlet_id, payload.terminal_id, now]);
            await client.query("COMMIT");
            return mapBinding(inserted.rows[0]);
        }
        catch (error) {
            await client.query("ROLLBACK");
            throw error;
        }
    });
    return result;
}
export async function unbindDevice(deviceId) {
    const now = nowIso();
    const { rows } = await getPool().query(`UPDATE device_bindings
        SET active_flag = FALSE,
            unbound_at = $2
      WHERE device_id = $1 AND active_flag = TRUE
      RETURNING *`, [deviceId, now]);
    return rows[0] ? mapBinding(rows[0]) : null;
}
export async function getBindingById(id) {
    const { rows } = await getPool().query("SELECT * FROM device_bindings WHERE id = $1", [id]);
    return rows[0] ? mapBinding(rows[0]) : null;
}
export function toBindingPayload(binding) {
    return { ...binding };
}
