import { Router } from 'express';
import { agentRequest, publicNode } from '../agentClient.js';
import { config } from '../config.js';
import { createAuditEvent, createNode, deleteNode, getNode, listNodes, recordNodeHealth, updateNode } from '../store.js';

export const nodesRouter = Router();

nodesRouter.get('/', (_req, res) => {
  res.json(listNodes().map(publicNode));
});

nodesRouter.post('/', async (req, res, next) => {
  try {
    const node = createNode(validateNodeInput(req.body));
    createAuditEvent({ user: req.user, action: 'create', targetType: 'node', targetId: node.id, details: { name: node.name, baseUrl: node.baseUrl } });
    res.status(201).json(publicNode(node));
  } catch (error) {
    next(error);
  }
});

nodesRouter.put('/:nodeId', async (req, res, next) => {
  try {
    const node = updateNode(req.params.nodeId, validateNodeInput(req.body, { partial: true }));
    if (!node) {
      res.status(404).json({ error: 'Node not found.' });
      return;
    }
    createAuditEvent({ user: req.user, action: 'update', targetType: 'node', targetId: node.id, details: { name: node.name, baseUrl: node.baseUrl, enabled: node.enabled } });
    res.json(publicNode(node));
  } catch (error) {
    next(error);
  }
});

nodesRouter.delete('/:nodeId', (req, res) => {
  createAuditEvent({ user: req.user, action: 'delete', targetType: 'node', targetId: req.params.nodeId });
  deleteNode(req.params.nodeId);
  res.json({ ok: true });
});

nodesRouter.get('/:nodeId/health', async (req, res, next) => {
  try {
    const node = requireNode(req.params.nodeId);
    const health = await agentRequest(node, '/health', { timeout: 10000 });
    recordNodeHealth(node.id, health?.ok ? 'ok' : 'degraded');
    res.json(health);
  } catch (error) {
    if (error.status === 404) {
      next(error);
      return;
    }
    recordNodeHealth(req.params.nodeId, 'error');
    next(error);
  }
});

nodesRouter.post('/:nodeId/test', async (req, res, next) => {
  try {
    const node = requireNode(req.params.nodeId);
    const health = await agentRequest(node, '/health', { timeout: 10000 });
    recordNodeHealth(node.id, health?.ok ? 'ok' : 'degraded');
    res.json({ ok: true, health });
  } catch (error) {
    recordNodeHealth(req.params.nodeId, '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;
}

function validateNodeInput(body, options = {}) {
  const values = body || {};
  const required = !options.partial;
  const name = values.name === undefined ? undefined : String(values.name).trim();
  const baseUrl = values.baseUrl === undefined ? undefined : String(values.baseUrl).trim();
  const token = values.token === undefined ? undefined : String(values.token).trim();

  if (required && (!name || !baseUrl || !token)) {
    const error = new Error('Node name, URL and token are required.');
    error.status = 400;
    throw error;
  }
  if (baseUrl) validateBaseUrl(baseUrl);

  return {
    ...(name !== undefined ? { name } : {}),
    ...(baseUrl !== undefined ? { baseUrl } : {}),
    ...(token !== undefined ? { token } : {}),
    ...(values.enabled !== undefined ? { enabled: Boolean(values.enabled) } : {}),
  };
}

function validateBaseUrl(baseUrl) {
  const url = new URL(baseUrl);
  if (url.protocol === 'https:') return;
  if (url.protocol === 'http:' && config.allowInsecureAgentHttp) {
    console.warn(`ALLOW_INSECURE_AGENT_HTTP=true permits insecure agent URL: ${baseUrl}`);
    return;
  }
  const error = new Error('Node URL must use https://. Set ALLOW_INSECURE_AGENT_HTTP=true only for local development.');
  error.status = 400;
  throw error;
}
