import type { LocationQuery, LocationQueryRaw, Router } from 'vue-router';

const LIST_RETURN_QUERY_KEY = 'returnTo';
const MAX_LIST_RETURN_LENGTH = 4096;

function hasUnsafeReturnCharacter(value: string): boolean {
  for (const character of value) {
    const codePoint = character.codePointAt(0) || 0;
    if (character === '\\' || codePoint <= 31 || codePoint === 127) {
      return true;
    }
  }
  return false;
}

function readListReturnTo(query: LocationQuery): string {
  const value = query[LIST_RETURN_QUERY_KEY];
  const normalized = Array.isArray(value) ? value[0] : value;
  return normalized === null || normalized === undefined
    ? ''
    : String(normalized);
}

function withListReturnTo(
  returnTo: string,
  query: LocationQueryRaw = {},
): LocationQueryRaw {
  return {
    ...query,
    [LIST_RETURN_QUERY_KEY]: returnTo,
  };
}

function resolveListReturnPath(
  router: Router,
  query: LocationQuery,
  allowedListPaths: readonly string[],
  fallbackPath: string,
): string {
  const raw = readListReturnTo(query);
  if (
    !raw ||
    raw.length > MAX_LIST_RETURN_LENGTH ||
    !raw.startsWith('/') ||
    raw.startsWith('//') ||
    hasUnsafeReturnCharacter(raw)
  ) {
    return fallbackPath;
  }

  try {
    const parsed = new URL(raw, 'https://easyflow.local');
    if (parsed.origin !== 'https://easyflow.local' || parsed.hash) {
      return fallbackPath;
    }
    if (!allowedListPaths.includes(parsed.pathname)) {
      return fallbackPath;
    }
    const resolved = router.resolve(raw);
    return resolved.matched.length > 0 ? resolved.fullPath : fallbackPath;
  } catch {
    return fallbackPath;
  }
}

function resolveHistoryBackPath(router: Router): string {
  if (typeof window === 'undefined') return '';
  const raw = window.history.state?.back;
  if (typeof raw !== 'string' || !raw) return '';
  const hashIndex = raw.indexOf('#');
  const candidate = hashIndex === -1 ? raw : raw.slice(hashIndex + 1);
  if (!candidate.startsWith('/')) return '';
  try {
    return router.resolve(candidate).fullPath;
  } catch {
    return '';
  }
}

async function navigateBackToList(
  router: Router,
  query: LocationQuery,
  allowedListPaths: readonly string[],
  fallbackPath: string,
): Promise<void> {
  const target = resolveListReturnPath(
    router,
    query,
    allowedListPaths,
    fallbackPath,
  );
  if (resolveHistoryBackPath(router) === target) {
    router.back();
    return;
  }
  await router.replace(target);
}

export {
  LIST_RETURN_QUERY_KEY,
  navigateBackToList,
  readListReturnTo,
  resolveListReturnPath,
  withListReturnTo,
};
