import { type WsFilePath, WsPath } from './ws-path';

const IGNORED_DIRECTORY_NAMES = new Set([
  '__macosx',
  '__pycache__',
  'bower_components',
  'build',
  'coverage',
  'dist',
  'node_modules',
  'out',
  'target',
  'temp',
  'tmp',
  'vendor',
]);

const IGNORED_FILE_NAMES = new Set(['desktop.ini', 'thumbs.db']);

/**
 * Chromium's File System Access API writes `<name>.crswap` swap files next
 * to real content while a writable stream is open. They can surface through
 * directory listings and file watchers mid-write and must never be treated
 * as workspace content.
 *
 * Deliberately narrow: broader temp suffixes like `.tmp`/`.swp` can be
 * legitimate user files (and the asset pipeline accepts them), so hiding or
 * suppressing their changes would leave visible workspace content stale.
 */
const CHROMIUM_SWAP_FILE_SUFFIX = '.crswap';

function pathSegments(filePath: WsFilePath): readonly string[] {
  return filePath.path.split('/').filter(Boolean);
}

export function isIgnoredWorkspacePathSegment(segment: string): boolean {
  return (
    segment.startsWith('.') ||
    IGNORED_DIRECTORY_NAMES.has(segment.toLowerCase())
  );
}

export function isVisibleWorkspaceDirectoryName(name: string): boolean {
  return !isIgnoredWorkspacePathSegment(name);
}

export function isVisibleWorkspaceFilePath(
  wsPath: string | WsFilePath,
): wsPath is WsFilePath {
  const filePath = WsPath.safeParseFile(wsPath).data;
  if (!filePath) {
    return false;
  }

  const segments = pathSegments(filePath);
  const fileName = segments.at(-1);
  if (!fileName) {
    return false;
  }

  const parentSegments = segments.slice(0, -1);
  if (
    parentSegments.some((segment) => isIgnoredWorkspacePathSegment(segment))
  ) {
    return false;
  }

  if (fileName.toLowerCase().endsWith(CHROMIUM_SWAP_FILE_SUFFIX)) {
    return false;
  }

  if (filePath.isNote()) {
    return parentSegments.length === 0 || !fileName.startsWith('.');
  }

  if (
    fileName.startsWith('.') ||
    IGNORED_FILE_NAMES.has(fileName.toLowerCase())
  ) {
    return false;
  }

  return true;
}
