import { Router, Request, Response } from 'express';
import { param } from '../utils/params';
import { execFile } from 'child_process';
import { promisify } from 'util';
import fs from 'fs/promises';
import path from 'path';
import { getSlugEntry } from '../services/registry.service';
import { logger } from '../utils/logger';

const execFileAsync = promisify(execFile);
const router = Router();

/** Validate a git branch name — prevent shell injection. */
const SAFE_BRANCH = /^[a-zA-Z0-9][a-zA-Z0-9_.\/-]{0,99}$/;

// POST /instance/:slug/upgrade/start — Run upgrade.sh
router.post('/instance/:slug/upgrade/start', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const { skipBackup, useRegistry, branch } = req.body || {};

  // SECURITY: Validate branch name to prevent injection
  if (branch && !SAFE_BRANCH.test(branch)) {
    res.status(400).json({ error: 'VALIDATION', message: 'Invalid branch name' });
    return;
  }

  const scriptPath = path.join(entry.basePath, 'scripts', 'upgrade.sh');
  try {
    await fs.access(scriptPath);
  } catch {
    res.status(400).json({ error: 'NOT_FOUND', message: 'upgrade.sh not found' });
    return;
  }

  // SECURITY: Use execFile with args array — no shell interpolation
  const args = ['--api-mode', '--force'];
  if (skipBackup) args.push('--skip-backup');
  if (useRegistry) args.push('--use-registry');
  if (branch) args.push('--branch', branch);

  // Fire-and-forget — CCP polls progress
  execFileAsync('bash', [scriptPath, ...args], {
    cwd: entry.basePath,
    timeout: 600_000,
    maxBuffer: 10 * 1024 * 1024,
  }).catch((err) => {
    logger.error(`[upgrade] ${param(req, 'slug')} failed: ${(err as Error).message}`);
  });

  res.json({ started: true });
});

// GET /instance/:slug/upgrade/progress — Read progress.json
router.get('/instance/:slug/upgrade/progress', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const progressPath = path.join(entry.basePath, 'data', 'upgrade', 'progress.json');

  try {
    const content = await fs.readFile(progressPath, 'utf-8');
    res.json(JSON.parse(content));
  } catch {
    res.json({ phase: 0, percentage: 0, message: 'Waiting for upgrade to start...' });
  }
});

// GET /instance/:slug/upgrade/result — Read result.json
router.get('/instance/:slug/upgrade/result', async (req: Request, res: Response) => {
  const entry = await getSlugEntry(param(req, 'slug'));
  const resultPath = path.join(entry.basePath, 'data', 'upgrade', 'result.json');

  try {
    const content = await fs.readFile(resultPath, 'utf-8');
    res.json(JSON.parse(content));
  } catch {
    res.status(404).json({ error: 'NOT_FOUND', message: 'No upgrade result available' });
  }
});

export default router;
