import { spawnCommand, runRestic } from './executor.js';

const vmNamePattern = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/;
const snapshotIdPattern = /^[A-Fa-f0-9]{8,64}$/;

export function assertVmNameShape(vmName) {
  if (!vmNamePattern.test(vmName || '')) {
    const error = new Error('Invalid VM name.');
    error.status = 400;
    throw error;
  }
}

export function assertSnapshotIdShape(snapshotId) {
  if (snapshotId === 'latest') return;
  if (!snapshotIdPattern.test(snapshotId || '')) {
    const error = new Error('Invalid snapshot id.');
    error.status = 400;
    throw error;
  }
}

export async function listIncusInstances() {
  const result = await spawnCommand('incus', ['list', '--format', 'json']);
  const entries = JSON.parse(result.stdout || '[]');
  return entries.filter((entry) => ['virtual-machine', 'container'].includes(entry.type));
}

export async function listIncusVms() {
  return listIncusInstances();
}

export async function validateVmExists(instanceName) {
  assertVmNameShape(instanceName);
  const instances = await listIncusInstances();
  const instance = instances.find((entry) => entry.name === instanceName);
  if (!instance) {
    const error = new Error(`Instance "${instanceName}" was not found.`);
    error.status = 404;
    throw error;
  }
  return instance;
}

export async function listSnapshotsForVm(vmName) {
  await validateVmExists(vmName);
  const result = await runRestic(['--no-lock', 'snapshots', '--json', '--tag', vmName]);
  const snapshots = JSON.parse(result.stdout || '[]');
  return snapshots
    .filter((snapshot) => !(snapshot.tags || []).includes('metadata'))
    .sort((a, b) => String(b.time || '').localeCompare(String(a.time || '')));
}

export async function validateSnapshotForVm(vmName, snapshotId) {
  assertSnapshotIdShape(snapshotId);
  const snapshots = await listSnapshotsForVm(vmName);
  if (snapshotId === 'latest') {
    if (!snapshots.length) {
      const error = new Error(`No snapshots found for ${vmName}.`);
      error.status = 404;
      throw error;
    }
    return snapshots[0];
  }

  const snapshot = snapshots.find((entry) => entry.id?.startsWith(snapshotId));
  if (!snapshot) {
    const error = new Error(`Snapshot "${snapshotId}" was not found for ${vmName}.`);
    error.status = 404;
    throw error;
  }
  return snapshot;
}
