import { getTemplate, normalizeFieldValues } from './robotComponents.js';

export const ROBOT_SCHEMA_VERSION = 1;

/**
 * @param {string} deviceId
 * @returns {{ version: number, device: string, components: { kind: string, fields: Record<string, string> }[] }}
 */
export function createEmptyRobotFile(deviceId) {
  return {
    version: ROBOT_SCHEMA_VERSION,
    device: deviceId,
    components: [],
  };
}

/**
 * @param {unknown} data
 * @returns {asserts data is { version: number, device: string, components: unknown[] }}
 */
function assertShape(data) {
  if (!data || typeof data !== 'object') throw new Error('Robot file must be a JSON object');
  const d = /** @type {{ version?: unknown, device?: unknown, components?: unknown }} */ (data);
  if (d.version !== ROBOT_SCHEMA_VERSION) {
    throw new Error(`Unsupported robot file version (expected ${ROBOT_SCHEMA_VERSION})`);
  }
  if (typeof d.device !== 'string' || !d.device) throw new Error('Robot file needs a string "device" id');
  if (!Array.isArray(d.components)) throw new Error('Robot file needs a "components" array');
}

/**
 * @param {unknown} raw
 * @returns {{ version: number, device: string, components: { kind: string, fields: Record<string, string> }[] }}
 */
export function normalizeRobotFile(raw) {
  assertShape(raw);
  const data = /** @type {{ version: number, device: string, components: unknown[] }} */ (raw);
  const components = [];
  for (let i = 0; i < data.components.length; i++) {
    const row = data.components[i];
    if (!row || typeof row !== 'object') throw new Error(`Invalid component at index ${i}`);
    const r = /** @type {{ kind?: unknown, fields?: unknown }} */ (row);
    if (typeof r.kind !== 'string' || !getTemplate(r.kind)) {
      throw new Error(`Unknown component kind: ${String(r.kind)}`);
    }
    const fields = normalizeFieldValues(r.kind, r.fields && typeof r.fields === 'object' ? r.fields : {});
    components.push({ kind: r.kind, fields });
  }
  return { version: data.version, device: data.device, components };
}

/**
 * @param {string} text
 */
export function parseRobotFileText(text) {
  let data;
  try {
    data = JSON.parse(text);
  } catch {
    throw new Error('Invalid JSON');
  }
  return normalizeRobotFile(data);
}
