/**
 * Folder Picker Utility
 * =====================
 * 
 * Handles directory selection with hybrid approach:
 * - File System Access API for Chromium browsers (best UX)
 * - webkitdirectory fallback for all other browsers
 * 
 * Based on the ChatGPT recommendation for "it just works" UX.
 */

export interface FileWithPath extends File {
  relativePath: string;
}

/**
 * Pick a directory using the best available method
 * @returns Promise<FileWithPath[]> - Array of files with relative paths
 * @throws 'fallback-input' - Indicates fallback input should be used
 */
export async function pickDirectory(): Promise<FileWithPath[]> {
  // Check if we have the modern File System Access API (Chromium)
  if ('showDirectoryPicker' in window) {
    try {
      const handle = await (window as any).showDirectoryPicker({
        mode: 'read'
      });
      
      const files: FileWithPath[] = [];
      await walkDirectoryHandle(handle, '', files);
      
      return files;
    } catch (error: any) {
      if (error.name === 'AbortError') {
        throw new Error('user-cancelled');
      }
      // Fall back to input method
      throw new Error('fallback-input');
    }
  }
  
  // No native directory picker support, use fallback
  throw new Error('fallback-input');
}

/**
 * Recursively walk directory handle and collect files
 * @param dirHandle - Directory handle from File System Access API
 * @param prefix - Current path prefix
 * @param files - Array to collect files
 */
async function walkDirectoryHandle(dirHandle: any, prefix: string, files: FileWithPath[]) {
  for await (const entry of dirHandle.values()) {
    if (entry.kind === 'file') {
      try {
        const file = await entry.getFile();
        const relativePath = `${prefix}${entry.name}`;
        
        // Add relative path property
        const fileWithPath = file as FileWithPath;
        fileWithPath.relativePath = relativePath;
        
        files.push(fileWithPath);
      } catch (error) {
        console.warn(`Failed to read file ${entry.name}:`, error);
      }
    } else if (entry.kind === 'directory') {
      // Recursively process subdirectory
      await walkDirectoryHandle(entry, `${prefix}${entry.name}/`, files);
    }
  }
}

/**
 * Process files from webkitdirectory input
 * @param fileList - FileList from input element
 * @returns FileWithPath[] - Array of files with relative paths
 */
export function processDirectoryFiles(fileList: FileList): FileWithPath[] {
  const files: FileWithPath[] = [];
  
  for (let i = 0; i < fileList.length; i++) {
    const file = fileList[i];
    
    // webkitRelativePath preserves the directory structure
    const relativePath = (file as any).webkitRelativePath || file.name;
    
    // Skip empty files (usually directories)
    if (file.size === 0 && relativePath.endsWith('/')) {
      continue;
    }
    
    const fileWithPath = file as FileWithPath;
    fileWithPath.relativePath = relativePath;
    
    files.push(fileWithPath);
  }
  
  return files;
}

/**
 * Calculate total size and file count for a file array
 * @param files - Array of files
 * @returns Object with total size and count
 */
export function calculateDirectoryStats(files: FileWithPath[]) {
  const totalSize = files.reduce((sum, file) => sum + file.size, 0);
  const fileCount = files.length;
  
  // Get unique directories
  const directories = new Set<string>();
  files.forEach(file => {
    const pathParts = file.relativePath.split('/');
    for (let i = 1; i < pathParts.length; i++) {
      directories.add(pathParts.slice(0, i).join('/'));
    }
  });
  
  return {
    fileCount,
    totalSize,
    directoryCount: directories.size,
    formattedSize: formatFileSize(totalSize)
  };
}

/**
 * Format file size in human-readable format
 * @param bytes - Size in bytes
 * @returns Formatted string
 */
export function formatFileSize(bytes: number): string {
  if (bytes === 0) return '0 Bytes';
  
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

/**
 * Create a directory tree structure from files
 * @param files - Array of files with relative paths
 * @returns Tree structure object
 */
export function createDirectoryTree(files: FileWithPath[]) {
  const tree: any = {};
  
  files.forEach(file => {
    const pathParts = file.relativePath.split('/');
    let currentLevel = tree;
    
    // Navigate through directory structure
    for (let i = 0; i < pathParts.length - 1; i++) {
      const dirName = pathParts[i];
      if (!currentLevel[dirName]) {
        currentLevel[dirName] = {
          type: 'directory',
          children: {},
          fileCount: 0,
          totalSize: 0
        };
      }
      currentLevel = currentLevel[dirName].children;
    }
    
    // Add file to the tree
    const fileName = pathParts[pathParts.length - 1];
    currentLevel[fileName] = {
      type: 'file',
      file: file,
      size: file.size,
      mimeType: file.type
    };
    
    // Update parent directory stats
    let statsLevel = tree;
    for (let i = 0; i < pathParts.length - 1; i++) {
      const dirName = pathParts[i];
      if (statsLevel[dirName]) {
        statsLevel[dirName].fileCount++;
        statsLevel[dirName].totalSize += file.size;
        statsLevel = statsLevel[dirName].children;
      }
    }
  });
  
  return tree;
}

/**
 * Check if directory picker is supported
 * @returns boolean
 */
export function isDirectoryPickerSupported(): boolean {
  return 'showDirectoryPicker' in window;
}

/**
 * Get browser compatibility info
 * @returns Object with compatibility details
 */
export function getBrowserCompatibility() {
  const isChromium = 'showDirectoryPicker' in window;
  const supportsWebkitDirectory = HTMLInputElement.prototype.hasOwnProperty('webkitdirectory');
  
  return {
    hasNativeDirectoryPicker: isChromium,
    hasWebkitDirectory: supportsWebkitDirectory,
    recommendedMethod: isChromium ? 'native' : 'fallback',
    browserType: isChromium ? 'chromium' : 'other'
  };
}
