import type { Locale } from '@redocly/theme/core/types';

import { DEFAULT_LOCALE_PLACEHOLDER } from '@redocly/theme/core/constants';

export function combineUrls(baseURL: string, ...relativeURLs: (string | undefined)[]) {
  let res = baseURL;
  for (let relativeURL of relativeURLs) {
    res = relativeURL
      ? res.replace(/[\/\\]+$/, '') + '/' + relativeURL.replace(/^[\/\\]+/, '')
      : res;
  }

  return res;
}

export function withPathPrefix(url: string) {
  return combineUrls(getPathPrefix(), url);
}

export function withoutPathPrefix(pathname: string) {
  const pathPrefix = getPathPrefix();
  return pathPrefix && pathname.startsWith(pathPrefix)
    ? pathname.slice(pathPrefix.length)
    : pathname;
}

export function withoutHash(url: undefined | null): undefined;
export function withoutHash(url: string): string;
export function withoutHash(url: string | undefined): string | undefined;
export function withoutHash(url: string | undefined | null): string | undefined {
  if (url == null) return undefined;
  return url.split('#')[0];
}

/**
 *
 * @returns url with leading and without trailing slash or empty string, e.g. '/prefix'
 */
export function getPathPrefix() {
  if (process.env.REDOCLY_PREFIX_PATHS) {
    return normalizePathPrefix(process.env.REDOCLY_PREFIX_PATHS);
  }

  return '';
}

export function normalizePathPrefix(prefix: string) {
  const withoutTrailing = removeTrailingSlash(prefix);
  return addLeadingSlash(withoutTrailing === '.' ? '' : withoutTrailing);
}

export function addLeadingSlash(url: string): string {
  return url.startsWith('/') ? url : `/${url}`;
}

export function removeTrailingSlash(url: string): string {
  return url.endsWith('/') ? url.substring(0, url.length - 1) : url;
}
export function removeLeadingSlash(url: string): string {
  return url.startsWith('/') ? url.substring(1) : url;
}

export function isPathInFolder(child: string, parent: string): boolean {
  parent = removeTrailingSlash(removeLeadingSlash(slash(parent)));
  child = removeTrailingSlash(removeLeadingSlash(slash(child)));
  return child === parent || child.startsWith(parent + '/');
}

/**
 * Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
 *
 * @param  path
 * @return  slashed path
 */
export function slash(path: string): string {
  const isExtendedLengthPath = /^\\\\\?\\/.test(path);

  if (isExtendedLengthPath) {
    return path;
  }

  return path.replace(/\\/g, `/`);
}

export function addTrailingSlash(url: string): string {
  return url.endsWith('/') ? url : `${url}/`;
}

/**
 * Adds locale to pathname, or replaces current locale in pathname with a new one
 * @param originalPathname - Pathname without path prefix
 * @param defaultLocale - Default locale code
 * @param newLocale - New locale code to apply
 * @param allLocales - Array of all available locales
 */
export function getPathnameForLocale(
  originalPathname: string,
  defaultLocale: string,
  newLocale: string,
  allLocales: Locale[],
) {
  const currentLocale = getLocaleFromPathname(originalPathname, defaultLocale, allLocales);

  if (currentLocale === newLocale) {
    return originalPathname;
  }

  const pathnameWithoutLocale =
    currentLocale === defaultLocale
      ? originalPathname
      : originalPathname.slice(currentLocale.length + 1);

  const newLocalePrefix = newLocale === defaultLocale ? '' : '/' + newLocale;

  return `${newLocalePrefix.toLowerCase()}${pathnameWithoutLocale}`;
}

/**
 * Extracts the locale code from a pathname
 * @param pathname - URL pathname to extract locale from without path prefix
 * @param defaultLocale - Default locale code to return if no locale found in pathname
 * @param allLocales - Array of all available locales to check against
 * @returns The locale code from the pathname, or the default locale if none found
 */
export function getLocaleFromPathname(
  pathname: string,
  defaultLocale: string = DEFAULT_LOCALE_PLACEHOLDER,
  allLocales: Locale[] = [],
) {
  const maybeLocale = pathname?.split('/')[1];
  const locale = allLocales.find((locale) => locale.code.toLowerCase() === maybeLocale);

  return locale?.code || defaultLocale;
}
