import { existsSync, readFileSync } from "node:fs";
import { isAbsolute } from "node:path";
import { rootPath } from "./config";

export type TransSshBackendPreference = "local-backend-core-broker" | "remote-frontend-websocket";

export interface TransSshBackendConfig {
  backend: TransSshBackendPreference;
  raw: string;
  sourceRef: string;
}

const defaultTransConfigPath = "/root/.unidesk/.env/trans.ymal";

export function readTransSshBackendConfig(env: NodeJS.ProcessEnv = process.env): TransSshBackendConfig | null {
  const configPath = resolveTransConfigPath(env);
  if (!existsSync(configPath.absolutePath)) return null;
  const parsed = asRecord(Bun.YAML.parse(readFileSync(configPath.absolutePath, "utf8")) as unknown, configPath.sourceRef);
  const kind = optionalString(parsed, "kind", configPath.sourceRef);
  if (kind !== null && kind !== "UniDeskTransConfig") {
    throw new Error(`${configPath.sourceRef}.kind must be UniDeskTransConfig`);
  }
  const ssh = optionalRecord(parsed, "ssh", configPath.sourceRef);
  if (ssh === null) return null;
  const raw = optionalString(ssh, "backend", `${configPath.sourceRef}.ssh`);
  if (raw === null) return null;
  const backend = normalizeTransSshBackend(raw, `${configPath.sourceRef}.ssh.backend`);
  if (backend === "auto") return null;
  return {
    backend,
    raw,
    sourceRef: `${configPath.sourceRef}#ssh.backend`,
  };
}

function resolveTransConfigPath(env: NodeJS.ProcessEnv): { absolutePath: string; sourceRef: string } {
  const configured = (env.UNIDESK_TRANS_CONFIG_PATH ?? env.UNIDESK_TRANS_YAML_PATH)?.trim();
  if (configured !== undefined && configured.length > 0) {
    return {
      absolutePath: isAbsolute(configured) ? configured : rootPath(configured),
      sourceRef: configured,
    };
  }
  return {
    absolutePath: rootPath(defaultTransConfigPath),
    sourceRef: defaultTransConfigPath,
  };
}

function normalizeTransSshBackend(raw: string, path: string): TransSshBackendPreference | "auto" {
  const normalized = raw.trim();
  if (normalized === "backend-core" || normalized === "local-backend-core-broker") return "local-backend-core-broker";
  if (normalized === "frontend-websocket" || normalized === "remote-frontend-websocket") return "remote-frontend-websocket";
  if (normalized === "auto") return "auto";
  throw new Error(`${path} must be one of: backend-core, local-backend-core-broker, frontend-websocket, remote-frontend-websocket, auto`);
}

function asRecord(value: unknown, path: string): Record<string, unknown> {
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path} must be an object`);
  return value as Record<string, unknown>;
}

function optionalRecord(obj: Record<string, unknown>, key: string, path: string): Record<string, unknown> | null {
  const value = obj[key];
  if (value === undefined) return null;
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path}.${key} must be an object`);
  return value as Record<string, unknown>;
}

function optionalString(obj: Record<string, unknown>, key: string, path: string): string | null {
  const value = obj[key];
  if (value === undefined) return null;
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path}.${key} must be a non-empty string`);
  return value;
}
