import { loadTextFile } from "./file-service.js";
import {
  gcodeProgramPath,
  machineIniPath,
  normalizeOpfsPath,
  parameterFilePath,
  sessionSnapshotPath,
  toolTablePath,
} from "./path-model.js";
import { loadMachineSessionSnapshot } from "./snapshot-store.js";

function checkResult(name, path, ok, error = null) {
  return {
    name,
    path,
    ok,
    error,
  };
}

async function checkTextFile(name, path, storage) {
  try {
    const text = await loadTextFile(path, storage);
    return {
      ...checkResult(name, path, true),
      bytes: text.length,
    };
  } catch (error) {
    return checkResult(name, path, false, error.message);
  }
}

function resolveReadinessPaths(machineId, options = {}) {
  const paths = {
    ini: options.iniOpfsPath ?? machineIniPath(machineId, options.iniFilename),
    parameters:
      options.parameterOpfsPath ?? parameterFilePath(machineId, options.parameterFilename),
    toolTable:
      options.toolTableOpfsPath ?? toolTablePath(machineId, options.toolTableFilename),
  };

  if (options.gcodeOpfsPath !== undefined) {
    paths.gcode = normalizeOpfsPath(options.gcodeOpfsPath);
  } else if (options.gcodeFilename !== undefined) {
    paths.gcode = gcodeProgramPath(options.gcodeFilename);
  }

  if (options.sessionId !== undefined) {
    paths.snapshot = sessionSnapshotPath(options.sessionId, options.snapshotFilename);
  }

  return paths;
}

function summarizeReadiness(checks, snapshotResult) {
  const failed = checks.filter((check) => !check.ok);
  const snapshotFailed = snapshotResult && !snapshotResult.ok ? [snapshotResult] : [];
  return [...failed, ...snapshotFailed];
}

export async function readMachineSessionReadiness(machineId, options = {}) {
  const paths = resolveReadinessPaths(machineId, options);
  const checks = [
    await checkTextFile("ini", paths.ini, options.storage),
    await checkTextFile("parameters", paths.parameters, options.storage),
    await checkTextFile("toolTable", paths.toolTable, options.storage),
  ];

  if (options.gcodeRequired === true || paths.gcode !== undefined) {
    checks.push(await checkTextFile("gcode", paths.gcode, options.storage));
  }

  let snapshot = null;
  let snapshotCheck = null;
  if (options.sessionId !== undefined) {
    try {
      snapshot = await loadMachineSessionSnapshot(options.sessionId, machineId, {
        storage: options.storage,
        filename: options.snapshotFilename,
      });
      snapshotCheck = checkResult("snapshot", paths.snapshot, true);
    } catch (error) {
      snapshotCheck = checkResult("snapshot", paths.snapshot, false, error.message);
    }
  }

  const failures = summarizeReadiness(checks, snapshotCheck);
  return {
    machineId,
    ready: failures.length === 0,
    phase: failures.length === 0 ? "ready" : "blocked",
    paths,
    checks,
    snapshotCheck,
    snapshot,
    missing: failures.map((failure) => failure.name),
    errors: failures.map((failure) => ({
      name: failure.name,
      path: failure.path,
      error: failure.error,
    })),
  };
}
