import { writeFileSync } from 'fs';
import { sync as mkdirpSync } from 'mkdirp';
import Path from 'path';
import { yellow, red, green } from 'chalk';

import readFile from './readFile';
import { header, subheader, footer } from './printer';
import readMessageFiles from './readMessageFiles';
import createSingleMessagesFile from './createSingleMessagesFile';
import printResults from './printResults';
import stringify from './stringify';

import core from './core';


const defaultJSONOptions = {
  space: 2,
  trailingNewline: false,
};

export default ({
  messagesDirectory,
  translationsDirectory,
  whitelistsDirectory = translationsDirectory,
  languages = [],
  singleMessagesFile = false,
  detectDuplicateIds = true,
  sortKeys = true,
  jsonOptions = {},
  overridePrinters = {},
}) => {
  if (!messagesDirectory || !translationsDirectory) {
    throw new Error('messagesDirectory and translationsDirectory are required');
  }

  const defaultPrinters = {
    printDuplicateIds(duplicateIds) {
      header('Duplicate ids:');
      if (duplicateIds.length) {
        duplicateIds.forEach(id => {
          console.log('  ', `Duplicate message id: ${red(id)}`);
        });
      } else {
        console.log(green('  No duplicate ids found, great!'));
      }
      footer();
    },

    printLanguageReport(langResults) {
      header(`Maintaining ${yellow(langResults.languageFilename)}:`);
      printResults({ ...langResults.report, sortKeys });
    }

   printNoLanguageFile(langResults) {
     subheader(`
        No existing ${langResults.languageFilename} translation file found.
        A new one is created.
      `);
    }

    printNoLanguageWhitelistFile(langResults) {
      subheader(```
        No existing ${langResults} file found.
        A new one is created.
      ```);
    }
  };

  const printers = {
    ...defaultPrinters,
    ...overridePrinters,
  }

  const stringifyOpts = {
    ...defaultJSONOptions,
    ...jsonOptions,
    sortKeys,
  };

  core(languages, {
    provideExtractedMessages: () => readMessageFiles(messagesDirectory),

    outputSingleFile: combinedFiles => {
      if (singleMessagesFile) {
        createSingleMessagesFile({
          messages: combinedFiles,
          directory: translationsDirectory,
          sortKeys,
        });
      }
    },

    outputDuplicateKeys: duplicateIds => {
      if (detectDuplicateIds) return;

      printers.printDuplicateIds(duplicateIds);
    },

    beforeReporting: () => {
      mkdirpSync(translationsDirectory);
      mkdirpSync(whitelistsDirectory);
    },

    provideLangTemplate: lang => {
      const languageFilename = `${lang}.json`;
      const languageFilepath = Path.join(translationsDirectory, languageFilename);
      const whitelistFilename = `whitelist_${lang}.json`;
      const whitelistFilepath = Path.join(whitelistsDirectory, whitelistFilename);

      return {
        lang,
        languageFilename,
        languageFilepath,
        whitelistFilename,
        whitelistFilepath,
      };
    },

    provideTranslationsFile: lang => {
      const filePath = Path.join(translationsDirectory, `${lang}.json`);
      const jsonFile = readFile(filePath);
      return jsonFile ? JSON.parse(jsonFile) : undefined;
    },

    provideWhitelistFile: lang => {
      const filePath = Path.join(whitelistsDirectory, `whitelist_${lang}.json`);
      const jsonFile = readFile(filePath);
      return jsonFile ? JSON.parse(jsonFile) : undefined;
    },

    reportLanguage: langResults => {
      if (!langResults.report.noTranslationFile && !langResults.report.noWhitelistFile) {
        printers.printLanguageReport(langResults);

        writeFileSync(
          langResults.languageFilepath,
          stringify(langResults.report.fileOutput, stringifyOpts),
        );
        writeFileSync(
          langResults.whitelistFilepath,
          stringify(langResults.report.whitelistOutput, stringifyOpts),
        );
      } else {
        if (langResults.report.noTranslationFile) {
          printers.printNoLanguageFile(langResults);
          writeFileSync(langResults, stringify(langResults.report.fileOutput, stringifyOpts));
        }

        if (langResults.report.noWhitelistFile) {
          printers.printNoLanguageWhitelistFile(langResults);
          writeFileSync(langResults.whitelistFilepath, stringify([], stringifyOpts));
        }
      }
    },
  });
};

@@ -461,17 +461,16 @@
 core';%0A%0A
-%0A
 const de
@@ -784,16 +784,44 @@
 s = %7B%7D,%0A
+  overrideCoreMethods = %7B%7D,%0A
 %7D) =%3E %7B%0A
@@ -1001,33 +1001,34 @@
 rintDuplicateIds
-(
+: 
 duplicateIds) %7B%0A
@@ -1023,17 +1023,19 @@
 icateIds
-)
+ =%3E
  %7B%0A     
@@ -1334,33 +1334,34 @@
 ntLanguageReport
-(
+: 
 langResults) %7B%0A 
@@ -1347,33 +1347,35 @@
 ort: langResults
-)
+ =%3E
  %7B%0A      header(
@@ -1493,18 +1493,20 @@
 );%0A    %7D
+,
 %0A%0A
+ 
    print
@@ -1511,33 +1511,34 @@
 ntNoLanguageFile
-(
+: 
 langResults) %7B%0A 
@@ -1528,28 +1528,31 @@
  langResults
-)
+ =%3E
  %7B%0A
+ 
      subhead
@@ -1673,24 +1673,25 @@
    %60);%0A    %7D
+,
 %0A%0A    printN
@@ -1704,33 +1704,34 @@
 ageWhitelistFile
-(
+: 
 langResults) %7B%0A 
@@ -1725,17 +1725,19 @@
 gResults
-)
+ =%3E
  %7B%0A     
@@ -1845,16 +1845,17 @@
 );%0A    %7D
+,
 %0A  %7D;%0A%0A 
@@ -1922,24 +1922,25 @@
 rinters,%0A  %7D
+;
 %0A%0A  const st
@@ -2030,21 +2030,32 @@
   co
-re(languages,
+nst defaultCoreMethods =
  %7B%0A 
@@ -4434,22 +4434,134 @@
     %7D%0A    %7D,
+%0A%0A    afterReporting: () =%3E %7B%7D,%0A  %7D;%0A%0A  core(languages, %7B%0A    ...defaultCoreMethods,%0A    ...overrideCoreMethods,
 %0A  %7D);%0A%7D;%0A

add ability to override single core methods