const WINDOWS_DRIVE_ROOT_PATTERN = /^[A-Za-z]:\/$/;
const WINDOWS_DRIVE_ABSOLUTE_PATTERN = /^[A-Za-z]:\//;

export const normalizeFilePath = (value: string | null | undefined): string => {
  if (typeof value !== 'string') {
    return '';
  }

  const trimmed = value.trim();
  if (!trimmed) {
    return '';
  }

  const withSlashes = trimmed.replace(/\\/g, '/');
  const hadUncPrefix = withSlashes.startsWith('//');
  let normalized = withSlashes.replace(/\/+/g, '/');

  if (hadUncPrefix && !normalized.startsWith('//')) {
    normalized = `/${normalized}`;
  }

  const isUnixRoot = normalized === '/';
  const isWindowsDriveRoot = WINDOWS_DRIVE_ROOT_PATTERN.test(normalized);
  if (!isUnixRoot && !isWindowsDriveRoot) {
    normalized = normalized.replace(/\/+$/, '');
  }

  return normalized;
};

export const isAbsoluteFilePath = (value: string | null | undefined): boolean => {
  const normalized = normalizeFilePath(value);
  return normalized.startsWith('/') || WINDOWS_DRIVE_ABSOLUTE_PATTERN.test(normalized);
};

const toComparableFilePath = (value: string | null | undefined): string => {
  const normalized = normalizeFilePath(value);
  return WINDOWS_DRIVE_ABSOLUTE_PATTERN.test(normalized) || normalized.startsWith('//')
    ? normalized.toLowerCase()
    : normalized;
};

const splitPathParts = (value: string): string[] => value.split('/').filter(Boolean);

const applyRelativeParts = (baseParts: string[], relativePath: string): string[] => {
  const stack = [...baseParts];
  for (const part of splitPathParts(relativePath)) {
    if (part === '.') {
      continue;
    }
    if (part === '..') {
      if (stack.length > 0) {
        stack.pop();
      }
      continue;
    }
    stack.push(part);
  }
  return stack;
};

export const toAbsoluteFilePath = (basePath: string | null | undefined, targetPath: string | null | undefined): string => {
  const normalizedTarget = normalizeFilePath(targetPath);
  if (!normalizedTarget) {
    return normalizeFilePath(basePath);
  }

  if (isAbsoluteFilePath(normalizedTarget)) {
    return normalizedTarget;
  }

  const normalizedBase = normalizeFilePath(basePath);
  if (!normalizedBase) {
    return normalizedTarget;
  }

  const drivePrefix = WINDOWS_DRIVE_ABSOLUTE_PATTERN.test(normalizedBase) ? normalizedBase.slice(0, 2) : '';
  const isUncBase = normalizedBase.startsWith('//');
  const isUnixBase = normalizedBase.startsWith('/') && !isUncBase;
  const baseRemainder = drivePrefix ? normalizedBase.slice(2) : normalizedBase;
  const parts = applyRelativeParts(splitPathParts(baseRemainder), normalizedTarget);
  const joined = parts.join('/');

  if (drivePrefix) {
    return joined ? `${drivePrefix}/${joined}` : `${drivePrefix}/`;
  }

  if (isUncBase) {
    return `//${joined}`;
  }

  if (isUnixBase) {
    return `/${joined}`;
  }

  return joined;
};

export const isFilePathWithinDirectory = (filePath: string | null | undefined, directory: string | null | undefined): boolean => {
  const normalizedFilePath = normalizeFilePath(filePath);
  const normalizedDirectory = normalizeFilePath(directory);
  if (!normalizedFilePath || !normalizedDirectory) {
    return false;
  }

  const comparablePath = toComparableFilePath(normalizedFilePath);
  const comparableDirectory = toComparableFilePath(normalizedDirectory);
  return comparablePath === comparableDirectory || comparablePath.startsWith(`${comparableDirectory}/`);
};

export const getRelativeFilePath = (filePath: string | null | undefined, directory: string | null | undefined): string => {
  const normalizedFilePath = normalizeFilePath(filePath);
  const normalizedDirectory = normalizeFilePath(directory);
  if (!normalizedFilePath) {
    return '';
  }

  if (!normalizedDirectory) {
    return normalizedFilePath;
  }

  if (toComparableFilePath(normalizedFilePath) === toComparableFilePath(normalizedDirectory)) {
    return '.';
  }

  if (!isFilePathWithinDirectory(normalizedFilePath, normalizedDirectory)) {
    return normalizedFilePath;
  }

  return normalizedFilePath.slice(normalizedDirectory.length + 1);
};

export const getDirectoryForFilePath = (currentDirectory: string | null | undefined, filePath: string | null | undefined): string => {
  const normalizedDirectory = normalizeFilePath(currentDirectory);
  const normalizedPath = normalizeFilePath(filePath);
  if (normalizedDirectory && (!normalizedPath || isFilePathWithinDirectory(normalizedPath, normalizedDirectory))) {
    return normalizedDirectory;
  }

  if (!normalizedPath) {
    return normalizedDirectory;
  }

  const lastSlash = normalizedPath.lastIndexOf('/');
  if (lastSlash === 0) {
    return '/';
  }
  if (lastSlash < 0) {
    return normalizedDirectory || normalizedPath;
  }

  if (/^[A-Za-z]:\//.test(normalizedPath) && lastSlash === 2) {
    return normalizedPath.slice(0, 3);
  }

  return normalizedPath.slice(0, lastSlash);
};
