'use strict';
const crypto = require('crypto');

class ServerApiClient {
    constructor(baseUrl) {
        this.baseUrl = baseUrl || process.env.TASK_SERVER_URL || 'http://localhost:4010';
        // Clave AES-256-GCM recibida en el register. Persiste para toda la vida del proceso.
        this._sessionKey = null;
    }

    async post(path, data = {}, timeoutMs = 10000) {
        const controller = new AbortController();
        const timer = setTimeout(() => controller.abort(), timeoutMs);
        try {
            const res = await fetch(`${this.baseUrl}${path}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data),
                signal: controller.signal,
            });
            if (!res.ok) {
                const text = await res.text();
                throw new Error(`HTTP ${res.status} ${path}: ${text}`);
            }
            return res.json();
        } finally {
            clearTimeout(timer);
        }
    }

    async get(path) {
        const res = await fetch(`${this.baseUrl}${path}`);
        if (!res.ok) throw new Error(`HTTP ${res.status} ${path}`);
        return res.json();
    }

    /**
     * Descifra un payload AES-256-GCM.
     * Espeja exactamente encryptPayload() del servidor (iv 96-bit, GCM, base64).
     */
    decryptPayload(payload) {
        if (!payload || !payload._enc || !this._sessionKey) return payload;
        try {
            const iv  = Buffer.from(payload.iv,   'base64');
            const tag = Buffer.from(payload.tag,  'base64');
            const enc = Buffer.from(payload.data, 'base64');
            const decipher = crypto.createDecipheriv('aes-256-gcm', this._sessionKey, iv);
            decipher.setAuthTag(tag);
            const plain = Buffer.concat([decipher.update(enc), decipher.final()]);
            return JSON.parse(plain.toString('utf8'));
        } catch (e) {
            console.error('[API] Error descifrando payload:', e.message, '— usando como está');
            return payload;
        }
    }

    async registerWorker(workerId, capabilities = ['REQUESTS', 'INBOX', 'FOLLOW'], hwid = null) {
        const res = await this.post('/workers/register', { workerId, capabilities, hwid });
        // Guardar la clave de sesión para descifrar payloads subsiguientes
        if (res?.sessionKey) {
            this._sessionKey = Buffer.from(res.sessionKey, 'hex');
        }
        return res;
    }

    async pullTask(workerId, timeoutMs = 45000) {
        const res = await this.post('/tasks/pull', { workerId }, timeoutMs);
        // Descifrar el payload si el servidor lo cifró con AES-256-GCM
        if (res?.task?.payload?._enc) {
            res.task.payload = this.decryptPayload(res.task.payload);
        }
        return res;
    }

    async heartbeat(taskId, workerId) {
        return this.post(`/tasks/${taskId}/heartbeat`, { workerId });
    }

    async reportResult(taskId, workerId, result) {
        return this.post(`/tasks/${taskId}/result`, { workerId, result });
    }

    async reportFailure(taskId, workerId, error) {
        return this.post(`/tasks/${taskId}/fail`, {
            workerId,
            error: error?.message || String(error),
        });
    }
}

module.exports = ServerApiClient;
