const DEFAULT_ONLYOFFICE_INTERNAL_URL = "http://127.0.0.1:8082";
const ONLYOFFICE_PROBE_PATH = "/web-apps/apps/api/documents/api.js";
const RESOLVE_CACHE_TTL_MS = 30_000;

const DEFAULT_ONLYOFFICE_INTERNAL_URL_CANDIDATES = [
  DEFAULT_ONLYOFFICE_INTERNAL_URL,
  "http://127.0.0.1:8081",
  "http://localhost:8082",
  "http://localhost:8081",
];

let cachedOnlyOfficeInternalUrl = "";
let cachedOnlyOfficeInternalUrlAt = 0;
let pendingOnlyOfficeInternalUrl: Promise<string> | null = null;

const normalizeOnlyOfficeInternalUrl = (raw?: string | null) => {
  const value = String(raw || "").trim().replace(/\/+$/, "");
  if (!value) return "";
  try {
    const url = new URL(value);
    if (url.protocol !== "http:" && url.protocol !== "https:") return "";
    return url.toString().replace(/\/+$/, "");
  } catch {
    return "";
  }
};

const getOnlyOfficeInternalUrlCandidates = () => {
  const candidates: string[] = [];
  const push = (value?: string | null) => {
    const normalized = normalizeOnlyOfficeInternalUrl(value);
    if (!normalized) return;
    if (!candidates.includes(normalized)) candidates.push(normalized);
  };

  push(process.env.ONLYOFFICE_INTERNAL_URL);

  for (const raw of String(process.env.ONLYOFFICE_INTERNAL_URL_CANDIDATES || "").split(",")) {
    push(raw);
  }

  for (const value of DEFAULT_ONLYOFFICE_INTERNAL_URL_CANDIDATES) {
    push(value);
  }

  return candidates.length > 0 ? candidates : [DEFAULT_ONLYOFFICE_INTERNAL_URL];
};

const probeOnlyOfficeInternalUrl = async (candidate: string) => {
  try {
    const probeUrl = new URL(ONLYOFFICE_PROBE_PATH, `${candidate}/`);
    const response = await fetch(probeUrl, {
      method: "HEAD",
      redirect: "follow",
      cache: "no-store",
      signal: AbortSignal.timeout(2_500),
    });
    return response.ok;
  } catch {
    return false;
  }
};

export const resolveOnlyOfficeInternalUrl = async () => {
  const now = Date.now();
  if (cachedOnlyOfficeInternalUrl && now - cachedOnlyOfficeInternalUrlAt < RESOLVE_CACHE_TTL_MS) {
    return cachedOnlyOfficeInternalUrl;
  }

  if (pendingOnlyOfficeInternalUrl) {
    return pendingOnlyOfficeInternalUrl;
  }

  pendingOnlyOfficeInternalUrl = (async () => {
    const candidates = getOnlyOfficeInternalUrlCandidates();
    for (const candidate of candidates) {
      if (await probeOnlyOfficeInternalUrl(candidate)) {
        return candidate;
      }
    }
    return candidates[0] || DEFAULT_ONLYOFFICE_INTERNAL_URL;
  })();

  try {
    const resolved = await pendingOnlyOfficeInternalUrl;
    cachedOnlyOfficeInternalUrl = resolved;
    cachedOnlyOfficeInternalUrlAt = Date.now();
    return resolved;
  } finally {
    pendingOnlyOfficeInternalUrl = null;
  }
};
