const uploads = "/wp-content/uploads/:year([0-9]{4})/:month([0-9]{2})";
const sizeSuffix = ":size(-[0-9]+x[0-9]+)?";
const safeName = /^[A-Za-z0-9._-]+$/;
const convertedRaster = /\.(?:png|jpe?g)\.webp$/i;

export type LegacyRedirect = {
  source: string;
  destination: string;
  statusCode: 301;
};
const redirect = (source: string, destination: string): LegacyRedirect => ({
  source,
  destination,
  statusCode: 301,
});
const splitExtension = (name: string) => {
  const dot = name.lastIndexOf(".");
  return dot < 1
    ? null
    : { base: name.slice(0, dot), extension: name.slice(dot + 1) };
};
const sourceFor = (name: string) => {
  const parts = splitExtension(name);
  return parts && `${uploads}/${parts.base}${sizeSuffix}.${parts.extension}`;
};

export function legacyUploadRedirects(
  shipped: readonly string[],
): readonly LegacyRedirect[] {
  const files = shipped
    .filter((name) => safeName.test(name))
    .toSorted(
      (left, right) =>
        right.length - left.length ||
        (left < right ? -1 : left > right ? 1 : 0),
    );
  const ruleFor = (requested: string, file: string) => {
    const source = sourceFor(requested);
    return source ? [redirect(source, `/images/${file}`)] : [];
  };
  const verbatim = files.flatMap((file) => ruleFor(file, file));
  const converted = files
    .filter((name) => convertedRaster.test(name))
    .flatMap((file) => ruleFor(file.slice(0, -".webp".length), file));
  return [...verbatim, ...converted].reduce<readonly LegacyRedirect[]>(
    (rules, rule) =>
      rules.some((existing) => existing.source === rule.source)
        ? rules
        : [...rules, rule],
    [],
  );
}

export const legacySitemapRedirects: readonly LegacyRedirect[] = [
  redirect("/wp-sitemap.xml", "/sitemap.xml"),
  redirect("/wp-sitemap-:section.xml", "/sitemap.xml"),
];
