/**
 * Docker context - Docker client and operations
 */
const Docker = require('dockerode');
const { DOCKER } = require('../utilities/constants');

const docker = new Docker();

/**
 * Pull a Docker image with timeout protection
 */
function dockerPull(imageName, timeoutMs = DOCKER.TIMEOUT) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(
      () => reject(new Error(`Docker pull timed out after ${timeoutMs / 1000}s: ${imageName}`)),
      timeoutMs
    );
    docker.pull(imageName, (err, stream) => {
      if (err) {
        clearTimeout(timer);
        return reject(err);
      }
      docker.modem.followProgress(stream, (err, output) => {
        clearTimeout(timer);
        if (err) return reject(err);
        resolve(output);
      });
    });
  });
}

/**
 * Find a running Docker container by name substring
 */
async function findContainerByName(name, opts = { all: false }) {
  const containers = await docker.listContainers(opts);
  const match = containers.find(c =>
    c.Names.some(n => n.toLowerCase().includes(name.toLowerCase()))
  );
  return match || null;
}

/**
 * Get all host ports currently in use by Docker containers
 */
async function getUsedPorts() {
  const containers = await docker.listContainers({ all: false });
  const ports = new Set();
  for (const c of containers) {
    for (const p of (c.Ports || [])) {
      if (p.PublicPort) ports.add(p.PublicPort);
    }
  }
  return ports;
}

function createDockerContext(dockerSecurity) {
  return {
    client: docker,
    pull: dockerPull,
    findContainer: findContainerByName,
    getUsedPorts,
    security: dockerSecurity,
  };
}

module.exports = { createDockerContext };
