import { Router } from 'express';
import { agentRequest } from '../agentClient.js';
import { createAuditEvent, createJobHistory, getNode, listNodes, recordNodeHealth, updateJobHistory } from '../store.js';

export const proxyRouter = Router();

proxyRouter.get('/health', async (_req, res) => {
  const nodes = listNodes().filter((node) => node.enabled);
  const checks = { database: 'ok' };
  let ok = true;
  await Promise.all(nodes.map(async (node) => {
    try {
      const health = await agentRequest(node, '/health', { timeout: 8000 });
      checks[node.name] = health?.ok ? 'ok' : 'degraded';
      recordNodeHealth(node.id, checks[node.name]);
      ok = ok && Boolean(health?.ok);
    } catch {
      checks[node.name] = 'error';
      recordNodeHealth(node.id, 'error');
      ok = false;
    }
  }));
  res.json({ ok, checks });
});

proxyRouter.get('/vms', async (_req, res) => {
  const nodes = listNodes().filter((node) => node.enabled);
  const rows = [];
  await Promise.all(nodes.map(async (node) => {
    try {
      const vms = await agentRequest(node, '/vms');
      for (const vm of vms) {
        rows.push({ ...vm, id: `${node.id}:${vm.name}`, nodeId: node.id, nodeName: node.name });
      }
      recordNodeHealth(node.id, 'ok');
    } catch {
      recordNodeHealth(node.id, 'error');
    }
  }));
  res.json(rows.sort((a, b) => `${a.nodeName}/${a.name}`.localeCompare(`${b.nodeName}/${b.name}`)));
});

proxyRouter.get('/jobs', async (_req, res) => {
  const nodes = listNodes().filter((node) => node.enabled);
  const rows = [];
  await Promise.all(nodes.map(async (node) => {
    try {
      const jobs = await agentRequest(node, '/jobs');
      for (const job of jobs) rows.push({ ...job, nodeId: node.id, nodeName: node.name });
    } catch {
      recordNodeHealth(node.id, 'error');
    }
  }));
  res.json(rows.sort((a, b) => String(b.startedAt || '').localeCompare(String(a.startedAt || ''))));
});

proxyRouter.get('/snapshots/:nodeId/:vmName', async (req, res, next) => {
  try {
    const node = requireNode(req.params.nodeId);
    const snapshots = await agentRequest(node, `/snapshots/${encodeURIComponent(req.params.vmName)}`);
    res.json(snapshots.filter((snapshot) => !(snapshot.tags || []).includes('metadata')));
  } catch (error) {
    next(error);
  }
});

proxyRouter.get('/snapshots/:nodeId/:vmName/:snapshotId/files', async (req, res, next) => {
  try {
    const node = requireNode(req.params.nodeId);
    res.json(await agentRequest(node, `/snapshots/${encodeURIComponent(req.params.vmName)}/${encodeURIComponent(req.params.snapshotId)}/files`));
  } catch (error) {
    next(error);
  }
});

proxyRouter.post('/backup/:nodeId/:vmName', async (req, res, next) => {
  const node = requireNode(req.params.nodeId);
  let historyId = null;
  try {
    const result = await agentRequest(node, `/backup/${encodeURIComponent(req.params.vmName)}`, { method: 'POST', body: req.body || {} });
    historyId = createJobHistory({ node, vmName: req.params.vmName, type: 'backup', agentJobId: result?.jobId, status: 'accepted' });
    createAuditEvent({ user: req.user, action: 'backup', targetType: 'vm', targetId: `${node.id}:${req.params.vmName}`, details: { historyId, agentJobId: result?.jobId } });
    res.status(202).json(result);
  } catch (error) {
    if (historyId) updateJobHistory(historyId, { status: 'failed', error: error.message });
    next(error);
  }
});

proxyRouter.post('/restore/:nodeId/:vmName', async (req, res, next) => {
  const node = requireNode(req.params.nodeId);
  let historyId = null;
  try {
    const result = await agentRequest(node, `/restore/${encodeURIComponent(req.params.vmName)}`, { method: 'POST', body: req.body || {} });
    historyId = createJobHistory({ node, vmName: req.params.vmName, type: 'restore', agentJobId: result?.jobId, status: 'accepted' });
    createAuditEvent({ user: req.user, action: 'restore', targetType: 'vm', targetId: `${node.id}:${req.params.vmName}`, details: { historyId, agentJobId: result?.jobId, snapshotId: req.body?.snapshotId } });
    res.status(202).json(result);
  } catch (error) {
    if (historyId) updateJobHistory(historyId, { status: 'failed', error: error.message });
    next(error);
  }
});

proxyRouter.get('/settings/:nodeId', async (req, res, next) => {
  try {
    const node = requireNode(req.params.nodeId);
    res.json(await agentRequest(node, '/settings'));
  } catch (error) {
    next(error);
  }
});

proxyRouter.put('/settings/:nodeId', async (req, res, next) => {
  try {
    const node = requireNode(req.params.nodeId);
    const result = await agentRequest(node, '/settings', { method: 'PUT', body: req.body || {} });
    createAuditEvent({ user: req.user, action: 'update', targetType: 'node-settings', targetId: node.id });
    res.json(result);
  } catch (error) {
    next(error);
  }
});

function requireNode(id) {
  const node = getNode(id);
  if (!node) {
    const error = new Error('Node not found.');
    error.status = 404;
    throw error;
  }
  return node;
}
