import path from 'path';
import fs from 'fs-extra';
import fsPromises from 'fs/promises';
import fsSync from 'fs';

// Types
export interface FileSystem {
  writeFile: typeof fs.writeFile;
  readFile: typeof fs.readFile;
  readdir: typeof fs.readdir;
  stat: typeof fs.stat;
  remove: typeof fs.remove;
  mkdir: typeof fs.mkdir;
  exists: (filePath: string) => Promise<boolean>;
  // Alias pour la compatibilité avec fs-extra
  pathExists: (filePath: string) => Promise<boolean>;
  ensureDir: typeof fs.ensureDir;
}

export const createFileSystem = (): FileSystem => {
  const existsImpl = async (filePath: string): Promise<boolean> => {
    try {
      await fsPromises.access(filePath);
      return true;
    } catch {
      return false;
    }
  };

  return {
    writeFile: fs.writeFile,
    readFile: fs.readFile,
    readdir: fs.readdir,
    stat: fs.stat,
    remove: fs.remove,
    mkdir: fs.mkdir,
    ensureDir: fs.ensureDir,
    exists: existsImpl,
    pathExists: existsImpl, // Alias pour compatibilité
  };
};

export const validateFileExists = async (fileSystem: FileSystem, filePath: string): Promise<boolean> => {
  return await fileSystem.exists(filePath);
};

export const ensureDirectoryExists = async (fileSystem: FileSystem, dirPath: string): Promise<void> => {
  const exists = await fileSystem.exists(dirPath);
  if (!exists) {
    await fileSystem.mkdir(dirPath, { recursive: true });
  }
};

export const writeFileContent = async (
  fileSystem: FileSystem,
  filePath: string,
  content: string,
  encoding: BufferEncoding = 'utf8'
): Promise<void> => {
  const dir = path.dirname(filePath);
  await ensureDirectoryExists(fileSystem, dir);
  await fileSystem.writeFile(filePath, content, encoding);
};

export const readFile = async (
  fileSystem: FileSystem,
  filePath: string,
  encoding: BufferEncoding = 'utf8'
): Promise<string> => {
  return await fileSystem.readFile(filePath, encoding);
};

export const fileExists = (filePath: string): boolean => {
  return fsSync.existsSync(filePath);
};

// Utility functions for common operations
export const createBackupFile = async (
  fileSystem: FileSystem,
  originalPath: string
): Promise<string> => {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  const backupPath = `${originalPath}.backup-${timestamp}`;
  
  const exists = await validateFileExists(fileSystem, originalPath);
  if (exists) {
    const content = await readFile(fileSystem, originalPath);
    await writeFileContent(fileSystem, backupPath, content);
  }
  
  return backupPath;
};

export const removeFile = async (
  fileSystem: FileSystem,
  filePath: string
): Promise<void> => {
  const exists = await validateFileExists(fileSystem, filePath);
  if (exists) {
    await fileSystem.remove(filePath);
  }
};

// Legacy exports for backward compatibility
export const createDirectory = async (dirPath: string): Promise<void> => {
  const fileSystem = createFileSystem();
  await ensureDirectoryExists(fileSystem, dirPath);
};

export const writeFile = async (filePath: string, content: string): Promise<void> => {
  const fileSystem = createFileSystem();
  await writeFileContent(fileSystem, filePath, content);
};

export const readDirectory = async (dirPath: string): Promise<string[]> => {
  const fileSystem = createFileSystem();
  return await fileSystem.readdir(dirPath);
};

export const getFileMetadata = async (filePath: string) => {
  const fileSystem = createFileSystem();
  return await fileSystem.stat(filePath);
};

export const buildFilePath = (...segments: string[]): string => {
  return path.join(...segments);
};

export interface FileOperationResult {
  success: boolean;
  error?: string;
}

// Pure functions for validation
export const validateDomainName = (domainName: string): boolean => {
  return /^[a-zA-Z0-9-_]+$/.test(domainName);
};

// Pure functions for error handling
export const getErrorMessage = (error: unknown): string => {
  return error instanceof Error ? error.message : 'Unknown error';
};

// Pure functions for file operations with results
export const executeFileOperationWithErrorHandling = async <T>(
  operation: () => Promise<T>
): Promise<FileOperationResult> => {
  try {
    await operation();
    return { success: true };
  } catch (error) {
    return { 
      success: false, 
      error: getErrorMessage(error)
    };
  }
};

export const getDomainPath = (basePath: string, domainName: string): string => 
  path.join(basePath, 'src', 'domains', domainName);

export const getDomainsBasePath = (basePath: string): string => 
  path.join(basePath, 'src', 'domains'); 