/**
 * Secure storage naming helpers.
 *
 * Goal: keep the original/display filename intact in the `documents` table
 * (title + file_name) so the UI and downloads stay human-readable, while
 * writing the actual object to storage under a sanitized + randomized key
 * that does not leak the document's real name through the public URL.
 */

/**
 * Extracts the file extension (lowercased, no dot). Falls back to "bin".
 */
export function getFileExtension(name: string, fallback = "bin"): string {
  if (!name) return fallback;
  const idx = name.lastIndexOf(".");
  if (idx <= 0 || idx === name.length - 1) return fallback;
  return name.slice(idx + 1).toLowerCase().replace(/[^a-z0-9]/g, "") || fallback;
}

/**
 * Sanitize a folder/path segment to be storage-safe.
 * Preserves "/" so that nested folder structures (e.g. "Resident Files/101")
 * still work as path prefixes.
 */
export function sanitizePathSegment(segment: string): string {
  if (!segment) return "";
  return segment
    .split("/")
    .map((part) =>
      part
        .replace(/[^a-zA-Z0-9._-]+/g, "_")
        .replace(/_+/g, "_")
        .replace(/^_+|_+$/g, "")
    )
    .filter(Boolean)
    .join("/");
}

/**
 * Build a randomized, opaque storage key for a file.
 *
 * The resulting path looks like:
 *   <prefix>/<yyyy>/<mm>/<random>.<ext>
 *
 * It contains zero information about the original filename, so the public
 * URL cannot be used to infer document contents.
 *
 * @param originalName  Original file name — used only to derive the extension.
 * @param prefix        Optional path prefix (e.g. "<associationId>/<folder>").
 *                      Will be sanitized; "/" is preserved for nesting.
 */
export function buildSecureStorageKey(
  originalName: string,
  prefix = "",
): string {
  const ext = getFileExtension(originalName);
  const random =
    typeof crypto !== "undefined" && "randomUUID" in crypto
      ? crypto.randomUUID().replace(/-/g, "")
      : `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`;

  const now = new Date();
  const yyyy = now.getUTCFullYear().toString();
  const mm = String(now.getUTCMonth() + 1).padStart(2, "0");

  const cleanPrefix = sanitizePathSegment(prefix);
  const tail = `${yyyy}/${mm}/${random}.${ext}`;
  return cleanPrefix ? `${cleanPrefix}/${tail}` : tail;
}

/**
 * Trigger a browser download for a remote file using the human-readable
 * display name, regardless of how it is stored in the bucket.
 *
 * Falls back to opening the URL in a new tab if the fetch fails (e.g. CORS
 * on a legacy URL).
 */
export async function downloadWithDisplayName(
  fileUrl: string,
  displayName: string,
): Promise<void> {
  if (!fileUrl) return;

  // Encode any spaces / special chars in legacy URLs.
  let safeUrl = fileUrl;
  try {
    safeUrl = encodeURI(decodeURI(fileUrl));
  } catch {
    /* noop */
  }

  // Make sure the saved name has an extension. If the display name lacks one,
  // borrow it from the storage URL.
  let outName = (displayName || "document").trim();
  if (!/\.[a-z0-9]{2,5}$/i.test(outName)) {
    const urlExt = getFileExtension(safeUrl.split("?")[0] || "", "");
    if (urlExt) outName = `${outName}.${urlExt}`;
  }

  try {
    const res = await fetch(safeUrl);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const blob = await res.blob();
    const objectUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = objectUrl;
    a.download = outName;
    document.body.appendChild(a);
    a.click();
    a.remove();
    setTimeout(() => URL.revokeObjectURL(objectUrl), 1000);
  } catch (err) {
    console.warn("[downloadWithDisplayName] Falling back to window.open:", err);
    window.open(safeUrl, "_blank");
  }
}
