/**
 * Worker Store
 * Persistence layer for workers (memory, redis, db)
 */
const now = () => new Date();
const mergeRecord = (current, patch) => ({
    ...current,
    ...patch,
    updatedAt: patch.updatedAt ?? now(),
});
const toSqlDateTime = (value) => {
    if (!value)
        return null;
    // Use UTC and drop timezone for SQL DATETIME compatibility
    return value.toISOString().slice(0, 19).replace('T', ' ');
};
const serializeDbWorker = (record) => ({
    name: record.name,
    queue_name: record.queueName,
    version: record.version,
    status: record.status,
    auto_start: record.autoStart,
    concurrency: record.concurrency,
    region: record.region,
    processor_spec: record.processorSpec ?? null,
    active_status: record.activeStatus ?? true,
    features: record.features ? JSON.stringify(record.features) : null,
    infrastructure: record.infrastructure ? JSON.stringify(record.infrastructure) : null,
    datacenter: record.datacenter ? JSON.stringify(record.datacenter) : null,
    created_at: toSqlDateTime(record.createdAt),
    updated_at: toSqlDateTime(record.updatedAt),
    last_health_check: toSqlDateTime(record.lastHealthCheck ?? null),
    last_error: record.lastError ?? null,
    connection_state: record.connectionState ?? null,
});
const getHealthCheck = (row) => {
    if (!row['last_health_check']) {
        return undefined;
    }
    return row['last_health_check'] instanceof Date
        ? row['last_health_check']
        : new Date(String(row['last_health_check']));
};
const deserializeDbWorker = (row) => {
    const parseJson = (value) => {
        if (typeof value !== 'string' || value.trim() === '')
            return null;
        try {
            return JSON.parse(value);
        }
        catch {
            return null;
        }
    };
    return {
        name: String(row['name'] ?? ''),
        queueName: String(row['queue_name'] ?? ''),
        version: row['version'] ? String(row['version']) : null,
        status: String(row['status'] ?? 'unknown'),
        autoStart: Boolean(row['auto_start'] ?? false),
        concurrency: Number(row['concurrency'] ?? 0),
        region: row['region'] ? String(row['region']) : null,
        processorSpec: String(row['processor_spec']),
        activeStatus: row['active_status'] === undefined ? true : Boolean(row['active_status']),
        features: parseJson(row['features']),
        infrastructure: parseJson(row['infrastructure']),
        datacenter: parseJson(row['datacenter']),
        createdAt: row['created_at'] instanceof Date ? row['created_at'] : new Date(String(row['created_at'])),
        updatedAt: row['updated_at'] instanceof Date ? row['updated_at'] : new Date(String(row['updated_at'])),
        lastHealthCheck: getHealthCheck(row),
        lastError: row['last_error'] ? String(row['last_error']) : undefined,
        connectionState: row['connection_state']
            ? String(row['connection_state'])
            : undefined,
    };
};
export const InMemoryWorkerStore = Object.freeze({
    create() {
        const store = new Map();
        return {
            async init() {
                return undefined;
            },
            async list(options) {
                let values = Array.from(store.values());
                if (options) {
                    const start = options.offset || 0;
                    const end = options.limit ? start + options.limit : undefined;
                    values = values.slice(start, end);
                }
                return values;
            },
            async get(name) {
                return store.get(name) ?? null;
            },
            async save(record) {
                store.set(record.name, record);
            },
            async update(name, patch) {
                const current = store.get(name);
                if (!current)
                    return;
                store.set(name, mergeRecord(current, patch));
            },
            async updateMany(names, patch) {
                for (const name of names) {
                    const current = store.get(name);
                    if (!current)
                        continue;
                    store.set(name, mergeRecord(current, patch));
                }
            },
            async remove(name) {
                store.delete(name);
            },
            async close() {
                // No-op for memory store
            },
        };
    },
});
export const RedisWorkerStore = Object.freeze({
    create(client, keyPrefix = 'workers:registry') {
        const key = keyPrefix;
        const serialize = (record) => JSON.stringify({
            ...record,
            createdAt: record.createdAt.toISOString(),
            updatedAt: record.updatedAt.toISOString(),
        });
        const deserialize = (raw) => {
            const parsed = JSON.parse(raw);
            return {
                ...parsed,
                createdAt: new Date(parsed.createdAt),
                updatedAt: new Date(parsed.updatedAt),
            };
        };
        return {
            async init() {
                return undefined;
            },
            async list(options) {
                const all = await client.hgetall(key);
                let values = Object.values(all).map((element) => deserialize(element));
                values.sort((a, b) => a.name.localeCompare(b.name));
                if (options) {
                    const start = options.offset || 0;
                    const end = options.limit ? start + options.limit : undefined;
                    values = values.slice(start, end);
                }
                return values;
            },
            async get(name) {
                const raw = await client.hget(key, name);
                return raw ? deserialize(raw) : null;
            },
            async save(record) {
                await client.hset(key, record.name, serialize(record));
            },
            async update(name, patch) {
                const current = await this.get(name);
                if (!current)
                    return;
                await client.hset(key, name, serialize(mergeRecord(current, patch)));
            },
            async updateMany(names, patch) {
                if (names.length === 0)
                    return;
                const entries = await client.hmget(key, ...names);
                const updates = [];
                entries.forEach((raw, index) => {
                    if (!raw)
                        return;
                    const current = deserialize(raw);
                    const updated = mergeRecord(current, patch);
                    updates.push(names[index], serialize(updated));
                });
                if (updates.length === 0)
                    return;
                await client.hset(key, ...updates);
            },
            async close() {
                try {
                    // Force disconnect in Cloudflare env to avoid hanging on quit()
                    client.disconnect();
                }
                catch {
                    // Ignore connection errors during cleanup
                }
            },
            async remove(name) {
                await client.hdel(key, name);
            },
        };
    },
});
export const DbWorkerStore = Object.freeze({
    create(db, table = 'zintrust_workers') {
        return {
            async init() {
                return undefined;
            },
            async list(options) {
                const query = db.table(table);
                if (options?.limit)
                    query.limit(options.limit);
                if (options?.offset)
                    query.offset(options.offset);
                const rows = await query.get();
                return rows.map((element) => deserializeDbWorker(element));
            },
            async get(name) {
                const row = await db.table(table).where('name', '=', name).first();
                return row ? deserializeDbWorker(row) : null;
            },
            async save(record) {
                const existing = await db
                    .table(table)
                    .where('name', '=', record.name)
                    .first();
                if (existing) {
                    await db.table(table).where('name', '=', record.name).update(serializeDbWorker(record));
                    return;
                }
                await db.table(table).insert(serializeDbWorker(record));
            },
            async update(name, patch) {
                const current = await this.get(name);
                if (!current)
                    return;
                const updated = mergeRecord(current, patch);
                await db.table(table).where('name', '=', name).update(serializeDbWorker(updated));
            },
            async updateMany(names, patch) {
                if (names.length === 0)
                    return;
                const update = {
                    updated_at: toSqlDateTime(patch.updatedAt ?? now()),
                };
                if (patch.status !== undefined)
                    update['status'] = patch.status;
                if (patch.lastError !== undefined)
                    update['last_error'] = patch.lastError ?? null;
                if (patch.lastHealthCheck !== undefined)
                    update['last_health_check'] = toSqlDateTime(patch.lastHealthCheck ?? null);
                if (patch.connectionState !== undefined)
                    update['connection_state'] = patch.connectionState ?? null;
                await db.table(table).whereIn('name', names).update(update);
            },
            async remove(name) {
                await db.table(table).where('name', '=', name).delete();
            },
            async close() {
                // Database clients often managed by pool, but if needed:
                // await db.destroy?.();
            },
        };
    },
});
