import { readFileSync } from "node:fs";
import { CliError } from "./errors.js";

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

export function readJsonFile(path: string, label: string): unknown {
  try {
    return JSON.parse(readFileSync(path, "utf8"));
  } catch (error) {
    if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
      throw new CliError("CLI 参数错误", "INPUT_NOT_FOUND", `${label} file not found: ${path}`, 2);
    }
    if (error instanceof SyntaxError) throw new CliError("CLI 参数错误", "INPUT_INVALID_JSON", `${label} file must be valid JSON: ${path}`, 2);
    throw error;
  }
}

export function parseBurstFile(path: string): [string[], number[]] {
  let raw = readJsonFile(path, "burst");
  if (isRecord(raw) && "bursts" in raw) raw = raw.bursts;
  if (isRecord(raw) && "burst_id" in raw && "burst_size" in raw && Array.isArray(raw.burst_id) && Array.isArray(raw.burst_size)) {
    const ids = raw.burst_id.map(String);
    const sizes = raw.burst_size.map(Number);
    if (ids.length !== sizes.length) throw new CliError("CLI 参数错误", "BURST_FILE_INVALID", "burst file burst_id and burst_size must have the same length", 2);
    return [ids, sizes];
  }
  if (Array.isArray(raw)) {
    return [
      raw.map((item) => {
        if (!isRecord(item) || !("id" in item) || !("size" in item)) throw new CliError("CLI 参数错误", "BURST_FILE_INVALID", "burst file items must contain id and size", 2);
        return String(item.id);
      }),
      raw.map((item) => Number((item as Record<string, unknown>).size)),
    ];
  }
  throw new CliError("CLI 参数错误", "BURST_FILE_INVALID", "burst file must be a JSON array or object with burst_id/burst_size", 2);
}

export function parseValveSettingFile(path: string): [string[], number[]] {
  const raw = readJsonFile(path, "valve-setting");
  if (isRecord(raw) && "valves" in raw && "valves_k" in raw && Array.isArray(raw.valves) && Array.isArray(raw.valves_k)) {
    const valves = raw.valves.map(String);
    const openings = raw.valves_k.map(Number);
    if (valves.length !== openings.length) throw new CliError("CLI 参数错误", "VALVE_SETTING_INVALID", "valves and valves_k must have the same length", 2);
    return [valves, openings];
  }
  if (Array.isArray(raw)) {
    return [
      raw.map((item) => {
        if (!isRecord(item) || !("valve" in item) || !("opening" in item)) throw new CliError("CLI 参数错误", "VALVE_SETTING_INVALID", "valve-setting items must contain valve and opening", 2);
        return String(item.valve);
      }),
      raw.map((item) => Number((item as Record<string, unknown>).opening)),
    ];
  }
  throw new CliError("CLI 参数错误", "VALVE_SETTING_INVALID", "valve-setting file must be a JSON array or object with valves/valves_k", 2);
}

export function assignDatasetKeys(target: Record<string, unknown>, path: string, keys: string[], label: string): void {
  const payload = readJsonFile(path, label);
  if (isRecord(payload)) {
    for (const key of keys) {
      if (key in payload) target[key] = payload[key];
    }
  }
}
