export interface JailConfig {
  name: string;
  hostname: string;
  ip: string;
  bridge?: string;
  gateway?: string;
  release?: string;
  path: string;
  runtime: WardenRuntimeKind;
  role: JailRole;
  provisioning: JailProvisioning;
  networking: JailNetworking;
  persistent: boolean;
  mountpoints: MountPoint[];
  environment: Record<string, string>;
  resources: ResourceLimits;
}

export type WardenRuntimeKind = 'freebsd-jail' | 'linux-vm';
export type JailRole =
  | 'control-plane'
  | 'worker'
  | 'networked-worker'
  | 'browser-vm';
export type JailProvisioning = 'thick' | 'thin' | 'clone' | 'image';
export type JailNetworking = 'shared' | 'vnet' | 'vm-bridged' | 'vm-nat';

export interface JailProfile {
  runtime: WardenRuntimeKind;
  role: JailRole;
  provisioning: JailProvisioning;
  networking: JailNetworking;
  persistent: boolean;
  baseRelease: string;
}

export const WARDEN_BRIDGE_NAME = 'warden0';
export const WARDEN_SUBNET_CIDR = '192.168.100.0/24';
export const WARDEN_SUBNET_PREFIX = 24;
export const WARDEN_GATEWAY_IP = '192.168.100.1';
export const WARDEN_CONTROL_PLANE_IP = '192.168.100.100';
export const WARDEN_WORKER_IP_START = 101;
export const WARDEN_CONTROL_PLANE_JAIL_ID = 'controlplane';
export const WARDEN_CONTROL_PLANE_HOSTNAME = 'ai.clawdie.si';
export const WARDEN_CONTROL_PLANE_RELEASE = '15.0-RELEASE';

export const WARDEN_JAIL_PROFILES: Record<
  'controlPlane' | 'worker' | 'networkedWorker' | 'browserVm',
  JailProfile
> = {
  controlPlane: {
    runtime: 'freebsd-jail',
    role: 'control-plane',
    provisioning: 'thick',
    networking: 'vnet',
    persistent: true,
    baseRelease: WARDEN_CONTROL_PLANE_RELEASE,
  },
  worker: {
    runtime: 'freebsd-jail',
    role: 'worker',
    provisioning: 'thin',
    networking: 'shared',
    persistent: false,
    baseRelease: WARDEN_CONTROL_PLANE_RELEASE,
  },
  networkedWorker: {
    runtime: 'freebsd-jail',
    role: 'networked-worker',
    provisioning: 'thin',
    networking: 'vnet',
    persistent: false,
    baseRelease: WARDEN_CONTROL_PLANE_RELEASE,
  },
  browserVm: {
    runtime: 'linux-vm',
    role: 'browser-vm',
    provisioning: 'image',
    networking: 'vm-bridged',
    persistent: true,
    baseRelease: 'linux-desktop-image',
  },
};

export interface MountPoint {
  source: string;
  destination: string;
  type: 'nullfs' | 'devfs' | 'tmpfs';
  options?: string;
}

export interface ResourceLimits {
  memoryMax?: string;
  cpuLimit?: number;
  processesMax?: number;
}

export const DEFAULT_JAIL_CONFIG: JailConfig = {
  name: WARDEN_CONTROL_PLANE_JAIL_ID,
  hostname: WARDEN_CONTROL_PLANE_HOSTNAME,
  ip: WARDEN_CONTROL_PLANE_IP,
  bridge: WARDEN_BRIDGE_NAME,
  gateway: WARDEN_GATEWAY_IP,
  release: WARDEN_CONTROL_PLANE_RELEASE,
  path: `/usr/local/bastille/jails/${WARDEN_CONTROL_PLANE_JAIL_ID}/root`,
  runtime: WARDEN_JAIL_PROFILES.controlPlane.runtime,
  role: WARDEN_JAIL_PROFILES.controlPlane.role,
  provisioning: WARDEN_JAIL_PROFILES.controlPlane.provisioning,
  networking: WARDEN_JAIL_PROFILES.controlPlane.networking,
  persistent: WARDEN_JAIL_PROFILES.controlPlane.persistent,
  mountpoints: [
    {
      source: '/home/clawdie/clawdie-ai',
      destination: '/home/clawdie/clawdie-ai',
      type: 'nullfs',
      options: 'ro',
    },
    {
      source: '/home/clawdie/.config/clawdie-cp',
      destination: '/home/clawdie/.config/clawdie-cp',
      type: 'nullfs',
      options: 'rw',
    },
    {
      source: 'devfs',
      destination: '/dev',
      type: 'devfs',
      options: 'ruleset=4',
    },
  ],
  environment: {
    NODE_ENV: 'production',
    WARDEN_RUNTIME: 'freebsd-jail',
    JAIL_NAME: WARDEN_CONTROL_PLANE_JAIL_ID,
  },
  resources: {
    memoryMax: '2G',
    cpuLimit: 2,
    processesMax: 1000,
  },
};

export function generateJailConfig(config: Partial<JailConfig> = {}): string {
  const finalConfig = { ...DEFAULT_JAIL_CONFIG, ...config };

  const lines: string[] = [
    `${finalConfig.name} {`,
    `  # Warden runtime: ${finalConfig.runtime}`,
    `  # Warden role: ${finalConfig.role}`,
    `  # Provisioning: ${finalConfig.provisioning}`,
    `  # Networking: ${finalConfig.networking}`,
    `  host.hostname = "${finalConfig.hostname}";`,
    `  ip4.addr = ${finalConfig.ip};`,
    finalConfig.gateway ? `  defaultrouter = "${finalConfig.gateway}";` : '',
    `  path = "${finalConfig.path}";`,
    '',
  ].filter(Boolean);

  finalConfig.mountpoints.forEach((mp) => {
    if (mp.type === 'nullfs') {
      lines.push(
        `  mount.fstab = "${mp.source} ${mp.destination} nullfs ${mp.options || 'ro'} 0 0";`,
      );
    } else if (mp.type === 'devfs') {
      lines.push(`  mount.devfs;`);
      lines.push(`  devfs_ruleset = 4;`);
    }
  });

  lines.push('');
  lines.push('  # Resource limits');
  if (finalConfig.resources.memoryMax) {
    lines.push(`  memoryuse = "max:${finalConfig.resources.memoryMax}";`);
  }
  if (finalConfig.resources.cpuLimit) {
    lines.push(`  cpuset.cpus = "0-${finalConfig.resources.cpuLimit - 1}";`);
  }
  if (finalConfig.resources.processesMax) {
    lines.push(`  maxproc = ${finalConfig.resources.processesMax};`);
  }

  lines.push('  exec.start = "/bin/sh /etc/rc";');
  lines.push('  exec.stop = "/bin/sh /etc/rc.shutdown";');
  lines.push('}');

  return lines.join('\n');
}

export function generateFstabEntries(config: JailConfig): string[] {
  const entries: string[] = [];

  config.mountpoints.forEach((mp) => {
    if (mp.type === 'nullfs') {
      entries.push(
        `${mp.source}\t${mp.destination}\tnullfs\t${mp.options || 'ro'}\t0\t0`,
      );
    }
  });

  return entries;
}

export function validateJailConfig(config: JailConfig): string[] {
  const errors: string[] = [];

  if (!config.name || !/^[a-z0-9_-]+$/i.test(config.name)) {
    errors.push('Jail name must be alphanumeric with dashes/underscores');
  }

  if (!config.hostname || !/^[a-z0-9.-]+$/i.test(config.hostname)) {
    errors.push('Invalid hostname format');
  }

  const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
  if (!ipRegex.test(config.ip)) {
    errors.push('Invalid IP address format');
  }

  if (config.bridge && !/^[a-z][a-z0-9_-]*[0-9]*$/i.test(config.bridge)) {
    errors.push('Invalid bridge interface format');
  }

  if (config.gateway && !ipRegex.test(config.gateway)) {
    errors.push('Invalid gateway IP address format');
  }

  if (!config.path || !config.path.startsWith('/')) {
    errors.push('Jail path must be absolute');
  }

  if (
    !['control-plane', 'worker', 'networked-worker', 'browser-vm'].includes(
      config.role,
    )
  ) {
    errors.push('Invalid jail role');
  }

  if (!['thick', 'thin', 'clone', 'image'].includes(config.provisioning)) {
    errors.push('Invalid jail provisioning mode');
  }

  if (!['shared', 'vnet', 'vm-bridged', 'vm-nat'].includes(config.networking)) {
    errors.push('Invalid jail networking mode');
  }

  if (!['freebsd-jail', 'linux-vm'].includes(config.runtime)) {
    errors.push('Invalid Warden runtime kind');
  }

  config.mountpoints.forEach((mp, index) => {
    if (!mp.source || !mp.destination) {
      errors.push(`Mountpoint ${index} missing source or destination`);
    }

    if (mp.type === 'nullfs' && !mp.source.startsWith('/')) {
      errors.push(`Mountpoint ${index} source must be absolute for nullfs`);
    }
  });

  return errors;
}

export function getDefaultJailConfigForProfile(
  profileName: keyof typeof WARDEN_JAIL_PROFILES,
): JailConfig {
  const profile = WARDEN_JAIL_PROFILES[profileName];

  if (profileName === 'controlPlane') {
    return { ...DEFAULT_JAIL_CONFIG };
  }

  if (profileName === 'browserVm') {
    return {
      ...DEFAULT_JAIL_CONFIG,
      name: 'warden-browser-vm',
      hostname: 'warden-browser-vm.clawdie.si',
      path: '/vm/warden-browser-vm',
      runtime: profile.runtime,
      role: profile.role,
      provisioning: profile.provisioning,
      networking: profile.networking,
      persistent: profile.persistent,
      release: profile.baseRelease,
      environment: {
        ...DEFAULT_JAIL_CONFIG.environment,
        JAIL_NAME: 'warden-browser-vm',
      },
    };
  }

  const suffix = profileName === 'worker' ? 'worker' : 'networked-worker';
  const workerOffset = profileName === 'worker' ? 0 : 49;
  return {
    ...DEFAULT_JAIL_CONFIG,
    name: `warden-${suffix}`,
    hostname: `warden-${suffix}.clawdie.si`,
    ip: `192.168.100.${WARDEN_WORKER_IP_START + workerOffset}`,
    path: `/usr/local/bastille/jails/warden-${suffix}/root`,
    runtime: profile.runtime,
    role: profile.role,
    provisioning: profile.provisioning,
    networking: profile.networking,
    persistent: profile.persistent,
    release: profile.baseRelease,
    environment: {
      ...DEFAULT_JAIL_CONFIG.environment,
      JAIL_NAME: `warden-${suffix}`,
    },
  };
}

export interface BastilleProvisionPlan {
  jailName: string;
  hostname: string;
  release: string;
  bridge: string;
  gateway: string;
  subnet: string;
  jailIp: string;
  createArgs: string[];
  startArgs: string[];
}

export function getControlPlaneBastillePlan(): BastilleProvisionPlan {
  return {
    jailName: DEFAULT_JAIL_CONFIG.name,
    hostname: DEFAULT_JAIL_CONFIG.hostname,
    release: DEFAULT_JAIL_CONFIG.release || WARDEN_CONTROL_PLANE_RELEASE,
    bridge: DEFAULT_JAIL_CONFIG.bridge || WARDEN_BRIDGE_NAME,
    gateway: DEFAULT_JAIL_CONFIG.gateway || WARDEN_GATEWAY_IP,
    subnet: WARDEN_SUBNET_CIDR,
    jailIp: DEFAULT_JAIL_CONFIG.ip,
    createArgs: [
      'create',
      '-T',
      '-B',
      '-g',
      DEFAULT_JAIL_CONFIG.gateway || WARDEN_GATEWAY_IP,
      DEFAULT_JAIL_CONFIG.name,
      DEFAULT_JAIL_CONFIG.release || WARDEN_CONTROL_PLANE_RELEASE,
      `${DEFAULT_JAIL_CONFIG.ip}/${WARDEN_SUBNET_PREFIX}`,
      DEFAULT_JAIL_CONFIG.bridge || WARDEN_BRIDGE_NAME,
    ],
    startArgs: ['start', DEFAULT_JAIL_CONFIG.name],
  };
}
