type AnyRecord = Record<string, any>;

export interface DisplayTimeConfig {
  timeZone: string;
  locale: string;
  label: string;
}

let cachedFrontendConfig: AnyRecord | null = null;
let cachedDisplayTimeConfig: DisplayTimeConfig | null = null;

export function readRootJsonAttribute(name: string, fallback: any): any {
  const raw = document.getElementById("root")?.getAttribute(name);
  if (!raw) return fallback;
  try {
    const parsed = JSON.parse(raw) as unknown;
    return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed as AnyRecord : fallback;
  } catch {
    return fallback;
  }
}

export function frontendConfig(): AnyRecord {
  if (cachedFrontendConfig !== null) return cachedFrontendConfig;
  const parsed = readRootJsonAttribute("data-config", null);
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
    throw new Error("frontend data-config is required");
  }
  cachedFrontendConfig = parsed as AnyRecord;
  return cachedFrontendConfig;
}

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

function validateTimeZone(timeZone: string): void {
  try {
    new Intl.DateTimeFormat("en-US", { timeZone }).format(new Date(0));
  } catch {
    throw new Error(`frontend displayTime.timeZone must be a valid IANA time zone, got ${timeZone}`);
  }
}

function validateLocale(locale: string): void {
  try {
    new Intl.DateTimeFormat(locale).format(new Date(0));
  } catch {
    throw new Error(`frontend displayTime.locale must be a valid Intl locale, got ${locale}`);
  }
}

export function displayTimeConfig(): DisplayTimeConfig {
  if (cachedDisplayTimeConfig !== null) return cachedDisplayTimeConfig;
  const displayTime = frontendConfig().displayTime;
  if (typeof displayTime !== "object" || displayTime === null || Array.isArray(displayTime)) {
    throw new Error("frontend data-config.displayTime is required");
  }
  const record = displayTime as AnyRecord;
  const config = {
    timeZone: requiredStringField(record, "timeZone", "frontend data-config.displayTime"),
    locale: requiredStringField(record, "locale", "frontend data-config.displayTime"),
    label: requiredStringField(record, "label", "frontend data-config.displayTime"),
  };
  validateTimeZone(config.timeZone);
  validateLocale(config.locale);
  cachedDisplayTimeConfig = config;
  return config;
}
