import { Router, Request, Response } from 'express';
import * as docker from '../services/docker.service';
import { getSlugEntry } from '../services/registry.service';
import { param } from '../utils/params';

const router = Router();

// GET /instance/:slug/ps
router.get('/instance/:slug/ps', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const containers = await docker.composePs(entry.basePath, entry.composeProject);
  res.json(containers);
});

// GET /instance/:slug/logs
router.get('/instance/:slug/logs', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const service = req.query.service as string | undefined;
  const tail = req.query.tail ? Number(req.query.tail) : 200;
  const since = req.query.since as string | undefined;
  const logs = await docker.composeLogs(entry.basePath, entry.composeProject, service, tail, since);
  res.json(logs);
});

// POST /instance/:slug/up
router.post('/instance/:slug/up', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const services = req.body?.services as string[] | undefined;
  const result = await docker.composeUp(entry.basePath, entry.composeProject, services);
  res.json(result);
});

// POST /instance/:slug/stop
router.post('/instance/:slug/stop', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const result = await docker.composeStop(entry.basePath, entry.composeProject);
  res.json(result);
});

// POST /instance/:slug/restart
router.post('/instance/:slug/restart', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const service = req.body?.service as string | undefined;
  const result = await docker.composeRestart(entry.basePath, entry.composeProject, service);
  res.json(result);
});

// POST /instance/:slug/down
router.post('/instance/:slug/down', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const removeVolumes = req.body?.removeVolumes === true;
  const result = await docker.composeDown(entry.basePath, entry.composeProject, removeVolumes);
  res.json(result);
});

// POST /instance/:slug/pull
router.post('/instance/:slug/pull', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const result = await docker.composePull(entry.basePath, entry.composeProject);
  res.json(result);
});

// POST /instance/:slug/build
router.post('/instance/:slug/build', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const result = await docker.composeBuild(entry.basePath, entry.composeProject);
  res.json(result);
});

// POST /instance/:slug/exec
router.post('/instance/:slug/exec', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const { service, command, envVars } = req.body;
  if (!service || !command) {
    res.status(400).json({ error: 'VALIDATION', message: 'service and command are required' });
    return;
  }

  // SECURITY: Reject shell metacharacters entirely — prevents `;`, `&&`, `|`, `$()`, backticks
  const SHELL_META = /[;&|`$(){}!><\n\r]/;
  if (SHELL_META.test(command)) {
    res.status(403).json({ error: 'FORBIDDEN', message: 'Command contains disallowed characters' });
    return;
  }

  // Command allowlist — only allow known safe command prefixes
  const allowedPatterns = [
    /^pg_dump\b/,
    /^npx\s+prisma\b/,
    /^cat\s/,
    /^ls\b/,
    /^echo\b/,
  ];
  if (!allowedPatterns.some((p) => p.test(command))) {
    res.status(403).json({ error: 'FORBIDDEN', message: 'Command not in allowlist' });
    return;
  }

  const result = await docker.composeExec(entry.basePath, entry.composeProject, service, command, undefined, envVars);
  res.json(result);
});

export default router;
