import { loadTextFile } from "./file-service.js";
import {
  machineIniPath,
  parameterFilePath,
  toolTablePath,
} from "./path-model.js";
import { restoreMachineParametersFromOpfs } from "./linuxcnc-parameter-bridge.js";
import { loadMachineToolTableFromOpfs } from "./linuxcnc-tool-table-bridge.js";

const DEFAULT_WASM_INI_PATH = "/work/machine.ini";
const DEFAULT_WASM_PARAMETER_PATH = "/work/linuxcnc.var";
const DEFAULT_WASM_TOOL_TABLE_PATH = "/work/tool.tbl";

function requireSessionSdk(interp) {
  if (typeof interp?.writeTextFile !== "function") {
    throw new Error("interpreter SDK is missing writeTextFile().");
  }
}

function requireIniSdk(iniSdk) {
  if (!iniSdk) {
    return;
  }
  for (const method of ["writeTextFile", "getString", "getBool"]) {
    if (typeof iniSdk[method] !== "function") {
      throw new Error(`INI SDK is missing ${method}().`);
    }
  }
}

function iniString(iniSdk, iniWasmPath, section, tag) {
  if (!iniSdk) {
    return undefined;
  }
  const value = iniSdk.getString(iniWasmPath, section, tag);
  return value === null || value === "" ? undefined : value;
}

function resolveSessionPaths(machineId, options = {}, iniValues = {}) {
  return {
    iniOpfsPath: options.iniOpfsPath ?? machineIniPath(machineId, options.iniFilename),
    iniWasmPath: options.iniWasmPath ?? DEFAULT_WASM_INI_PATH,
    parameterOpfsPath:
      options.parameterOpfsPath ??
      parameterFilePath(
        machineId,
        options.parameterFilename ?? iniValues.parameterFilename,
      ),
    parameterWasmPath: options.parameterWasmPath ?? DEFAULT_WASM_PARAMETER_PATH,
    toolTableOpfsPath:
      options.toolTableOpfsPath ??
      toolTablePath(machineId, options.toolTableFilename ?? iniValues.toolTableFilename),
    toolTableWasmPath: options.toolTableWasmPath ?? DEFAULT_WASM_TOOL_TABLE_PATH,
  };
}

function randomToolChangerFromIni(iniSdk, iniWasmPath, iniText) {
  if (!iniSdk) {
    return false;
  }

  iniSdk.writeTextFile(iniWasmPath, iniText);
  return iniSdk.getBool(iniWasmPath, "EMCIO", "RANDOM_TOOLCHANGER") === true;
}

export async function loadMachineSessionFromOpfs(interp, machineId, options = {}) {
  requireSessionSdk(interp);
  requireIniSdk(options.iniSdk);
  const iniPaths = resolveSessionPaths(machineId, options);
  const iniText = await loadTextFile(iniPaths.iniOpfsPath, options.storage);
  options.iniSdk?.writeTextFile(iniPaths.iniWasmPath, iniText);
  const paths = resolveSessionPaths(machineId, options, {
    parameterFilename: iniString(
      options.iniSdk,
      iniPaths.iniWasmPath,
      "RS274NGC",
      "PARAMETER_FILE",
    ),
    toolTableFilename: iniString(options.iniSdk, iniPaths.iniWasmPath, "EMCIO", "TOOL_TABLE"),
  });
  interp.writeTextFile(paths.iniWasmPath, iniText);
  const randomToolChanger =
    typeof options.randomToolChanger === "boolean"
      ? options.randomToolChanger
      : randomToolChangerFromIni(options.iniSdk, paths.iniWasmPath, iniText);

  const parameters = await restoreMachineParametersFromOpfs(interp, machineId, {
    storage: options.storage,
    opfsPath: paths.parameterOpfsPath,
    wasmPath: paths.parameterWasmPath,
  });
  const toolTable = await loadMachineToolTableFromOpfs(interp, machineId, {
    storage: options.storage,
    opfsPath: paths.toolTableOpfsPath,
    wasmPath: paths.toolTableWasmPath,
    randomToolChanger,
  });

  return {
    machineId,
    ini: {
      opfsPath: paths.iniOpfsPath,
      wasmPath: paths.iniWasmPath,
    },
    parameters,
    toolTable,
  };
}
