function normalizeString(value) {
  if (typeof value !== "string") {
    return "";
  }

  return value.trim();
}

function normalizeUsername(value) {
  return normalizeString(value).toLowerCase();
}

function parseOptionalDate(value) {
  const normalized = normalizeString(value);
  if (!normalized) {
    return null;
  }

  const parsed = new Date(normalized);
  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed.toISOString();
}

function parseTags(rawTags) {
  if (!rawTags) {
    return [];
  }

  return String(rawTags)
    .split(",")
    .map((tag) => tag.trim().toLowerCase())
    .filter(Boolean)
    .filter((tag, index, all) => all.indexOf(tag) === index);
}

function sanitizeObjectName(name) {
  return String(name)
    .replace(/[^a-zA-Z0-9._-]+/g, "_")
    .slice(0, 120);
}

function sanitizeFolderName(name) {
  const value = normalizeString(name)
    .replace(/[\\/]/g, "")
    .replace(/\s+/g, " ")
    .trim();

  if (!value || value === "." || value === "..") {
    return "";
  }

  return value.slice(0, 120);
}

function escapeQuoted(value) {
  return String(value).replace(/"/g, "'");
}

function normalizeSortField(value) {
  const normalized = normalizeString(value);
  const allowed = new Set(["uploadedAt", "clientLastModifiedAt", "displayName.keyword"]);
  if (allowed.has(normalized)) {
    return normalized;
  }

  if (normalized === "createdAt") {
    return "clientLastModifiedAt";
  }

  if (normalized === "name") {
    return "displayName.keyword";
  }

  return "uploadedAt";
}

function normalizeSortDirection(value) {
  const normalized = normalizeString(value).toLowerCase();
  return normalized === "asc" ? "asc" : "desc";
}

function buildDirectChildrenScopeQuery(folderPath) {
  return {
    bool: {
      should: [
        {
          bool: {
            must: [{ term: { entryType: "file" } }, { term: { folderPath } }]
          }
        },
        {
          bool: {
            must: [{ term: { entryType: "folder" } }, { term: { parentFolderPath: folderPath } }]
          }
        }
      ],
      minimum_should_match: 1
    }
  };
}

function buildRecursiveScopeQuery(folderPath) {
  if (!folderPath) {
    return { match_all: {} };
  }

  const descendantPrefix = `${folderPath}/`;
  return {
    bool: {
      should: [
        {
          bool: {
            must: [
              { term: { entryType: "file" } },
              {
                bool: {
                  should: [{ term: { folderPath } }, { prefix: { folderPath: descendantPrefix } }],
                  minimum_should_match: 1
                }
              }
            ]
          }
        },
        {
          bool: {
            must: [
              { term: { entryType: "folder" } },
              {
                bool: {
                  should: [{ term: { folderPath } }, { prefix: { folderPath: descendantPrefix } }],
                  minimum_should_match: 1
                }
              }
            ]
          }
        }
      ],
      minimum_should_match: 1
    }
  };
}

function normalizeFolderPath(value) {
  const raw = normalizeString(value);
  if (!raw || raw === "/") {
    return "";
  }

  const cleaned = raw
    .split("/")
    .map((segment) => segment.trim())
    .filter(Boolean)
    .filter((segment) => segment !== "." && segment !== "..")
    .map((segment) => segment.replace(/[\\/]/g, ""));

  return cleaned.length ? `/${cleaned.join("/")}` : "";
}

function buildFolderPath(parentFolderPath, name) {
  const parent = normalizeFolderPath(parentFolderPath);
  return `${parent}/${name}`.replace(/\/+/g, "/");
}

function parentPathOf(folderPath) {
  const normalized = normalizeFolderPath(folderPath);
  if (!normalized) {
    return "";
  }

  const parts = normalized.split("/").filter(Boolean);
  if (parts.length <= 1) {
    return "";
  }

  return `/${parts.slice(0, -1).join("/")}`;
}

function handleServerError(res, error, message) {
  console.error(message, error);
  res.status(500).json({
    error: message,
    details: error && error.message ? error.message : "unknown error"
  });
}

module.exports = {
  normalizeString,
  normalizeUsername,
  parseOptionalDate,
  parseTags,
  sanitizeObjectName,
  sanitizeFolderName,
  escapeQuoted,
  normalizeSortField,
  normalizeSortDirection,
  buildDirectChildrenScopeQuery,
  buildRecursiveScopeQuery,
  normalizeFolderPath,
  buildFolderPath,
  parentPathOf,
  handleServerError
};
