import path from 'path';
import fs from 'fs-extra';
import chalk from 'chalk';
import File, { find } from '../File';
import Todo, { find as findToDo } from '../Todo';

export interface Options {
  maxSize?: number,
  dryRun?: boolean,
  showChanges?: boolean,
  pattern?: string,
}

export const files = async (location: string, handler: (file: File) => Promise<void>, {
  dryRun = false,
  maxSize = 1000000 * 0.1,
  showChanges = true,
  pattern,
}: Options = {}) => {
  const fileList = await find(location, pattern);
  let updatedFiles = 0;
  let lines = 0;
  await Promise.all(fileList.map(async fileName => {
    const filePath = path.join(location, fileName);
    const stats = await fs.stat(filePath);
    if (stats.isFile() && (!maxSize || stats.size < maxSize)) {
      const content = await fs.readFile(filePath, 'utf-8');
      const file = new File(filePath, content, location);
      await handler(file);
      const relativePath = path.relative(process.cwd(), filePath);
      if (file.changed) {
        if (showChanges) {
          console.log(chalk.blue(relativePath));
          file.changes.forEach(change => {
            const line = file.lines[change];
            const original = file.original[change];

            console.log(`${chalk.red(change.toString())} before: ${chalk.gray(original)}`);
            console.log(`${chalk.red(change.toString())} after: ${chalk.white(line)}`);
            console.log();
          });
          updatedFiles++;
          lines += file.changes.length;
        }

        if (!dryRun) {
          await fs.writeFile(filePath, file.toString());
        }
      }
    }
  }));

  console.log([
    '\n',
    `changed ${chalk.cyan(updatedFiles.toString())} file${updatedFiles === 1 ? '' : 's'} `,
    `and ${chalk.cyan(lines.toString())} line${lines === 1 ? '' : 's'}`,
  ].join(''));
}

export const todos = async (file: File, handle: (todo: Todo) => Promise<void>) => {
  const todos = findToDo(file);
  await Promise.all(todos.map(async (todo) => {
    await handle(todo);
  }));
}