"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.validate = exports.staticSqlValidations = exports.postValidation = void 0;

var _chalk = _interopRequireDefault(require("chalk"));

var _singleLineLog = require("single-line-log");

var _tracker = require("../tracker");

var _prompt = require("../cli/prompt");

var _lineByLine = require("./line-by-line");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * 
 * @format
 */

/**
 * External dependencies
 */

/**
 * Internal dependencies
 */
let problemsFound = 0;
let lineNum = 1;

const errorCheckFormatter = check => {
  if (check.results.length > 0) {
    problemsFound += 1;
    console.error(_chalk.default.red('Error:'), `${check.message} on line(s) ${check.results.join(', ')}.`);
    console.error(_chalk.default.yellow('Recommendation:'), `${check.recommendation}`);
  } else {
    console.log(`✅ ${check.message} was found ${check.results.length} times.`);
  }
};

const requiredCheckFormatter = (check, type) => {
  if (check.results.length > 0) {
    console.log(`✅ ${check.message} was found ${check.results.length} times.`);

    if (type === 'createTable') {
      checkTablePrefixes(check.results);
    }
  } else {
    problemsFound += 1;
    console.error(_chalk.default.red('Error:'), `${check.message} was not found.`);
    console.error(_chalk.default.yellow('Recommendation:'), `${check.recommendation}`);
  }
};

const infoCheckFormatter = check => {
  check.results.forEach(item => {
    console.log(item);
  });
};

function checkTablePrefixes(tables) {
  const wpTables = [],
        notWPTables = [],
        wpMultisiteTables = [];
  tables.forEach(tableName => {
    if (tableName.match(/^wp_(\d+_)/)) {
      wpMultisiteTables.push(tableName);
    } else if (tableName.match(/^wp_/)) {
      wpTables.push(tableName);
    } else if (!tableName.match(/^wp_/)) {
      notWPTables.push(tableName);
    }
  });

  if (wpTables.length > 0) {
    console.log(` - wp_ prefix tables found: ${wpTables.length} `);
  }

  if (notWPTables.length > 0) {
    problemsFound += 1;
    console.error(_chalk.default.red('Error:'), `tables without wp_ prefix found: ${notWPTables.join(',')} `);
  }

  if (wpMultisiteTables.length > 0) {
    console.log(` - wp_n_ prefix tables found: ${wpMultisiteTables.length} `);
  }
}

const checks = {
  useDB: {
    matcher: /^use\s/i,
    matchHandler: lineNumber => lineNumber,
    outputFormatter: errorCheckFormatter,
    results: [],
    message: 'USE statement',
    excerpt: '\'USE\' statement should not be present (case-insensitive, at beginning of line)',
    recommendation: 'Remove these lines'
  },
  createDB: {
    matcher: /^CREATE DATABASE/i,
    matchHandler: lineNumber => lineNumber,
    outputFormatter: errorCheckFormatter,
    results: [],
    message: 'CREATE DATABASE statement',
    excerpt: '\'CREATE DATABASE\' statement should not  be present (case-insensitive)',
    recommendation: 'Remove these lines'
  },
  trigger: {
    matcher: /TRIGGER/,
    matchHandler: lineNumber => lineNumber,
    outputFormatter: errorCheckFormatter,
    results: [],
    message: 'TRIGGER statement',
    excerpt: '\'TRIGGER\' statement should not be present (case-sensitive)',
    recommendation: 'Remove these lines'
  },
  dropDB: {
    matcher: /^DROP DATABASE/i,
    matchHandler: lineNumber => lineNumber,
    outputFormatter: errorCheckFormatter,
    results: [],
    message: 'DROP DATABASE statement',
    excerpt: '\'DROP DATABASE\' should not be present (case-insensitive)',
    recommendation: 'Remove these lines'
  },
  alterUser: {
    matcher: /^(ALTER USER|SET PASSWORD)/i,
    matchHandler: lineNumber => lineNumber,
    outputFormatter: errorCheckFormatter,
    results: [],
    message: 'ALTER USER statement',
    excerpt: '\'ALTER USER\' should not be present (case-insensitive)',
    recommendation: 'Remove these lines'
  },
  dropTable: {
    matcher: /^DROP TABLE IF EXISTS `?([a-z0-9_]*)/i,
    matchHandler: (lineNumber, results) => results[1],
    outputFormatter: requiredCheckFormatter,
    results: [],
    message: 'DROP TABLE',
    excerpt: '\'DROP TABLE IF EXISTS\' should be present (case-insensitive)',
    recommendation: 'Check import settings to include DROP TABLE statements'
  },
  createTable: {
    matcher: /^CREATE TABLE `?([a-z0-9_]*)/i,
    matchHandler: (lineNumber, results) => results[1],
    outputFormatter: requiredCheckFormatter,
    results: [],
    message: 'CREATE TABLE',
    excerpt: '\'CREATE TABLE\' should be present (case-insensitive)',
    recommendation: 'Check import settings to include CREATE TABLE statements'
  },
  siteHomeUrl: {
    matcher: '\'(siteurl|home)\',\\s?\'(.*?)\'',
    matchHandler: (lineNumber, results) => results[0],
    outputFormatter: infoCheckFormatter,
    results: [],
    message: 'Siteurl/home matches',
    excerpt: 'Siteurl/home options',
    recommendation: ''
  },
  engineInnoDB: {
    matcher: /ENGINE=(?!(InnoDB))/i,
    matchHandler: lineNumber => lineNumber,
    outputFormatter: errorCheckFormatter,
    results: [],
    message: 'ENGINE != InnoDB',
    excerpt: '\'ENGINE=InnoDB\' should be present (case-insensitive) for all tables',
    recommendation: 'Ensure your application works with InnoDB and update your SQL dump to include only \'ENGINE=InnoDB\' engine definitions in \'CREATE TABLE\' statements'
  }
};

const postValidation = async (filename, isImport = false) => {
  await (0, _tracker.trackEvent)('import_validate_sql_command_execute', {
    is_import: isImport
  });
  console.log(`${_chalk.default.underline('Starting SQL Validation...')}`);
  (0, _singleLineLog.stdout)(`Finished processing ${lineNum} lines.`);
  console.log('\n');
  const errorSummary = {};
  const checkEntires = Object.entries(checks);

  for (const [type, check] of checkEntires) {
    check.outputFormatter(check, type);
    console.log('');
    errorSummary[type] = check.results.length;
  } // eslint-disable-next-line camelcase


  errorSummary.problems_found = problemsFound;

  if (problemsFound > 0) {
    console.error(`** Total of ${_chalk.default.red(problemsFound)} errors found ** `);

    if (isImport) {
      console.log(`${_chalk.default.red('Please adjust these error(s) before proceeding with the import.')}`);
      console.log();
    }

    await (0, _tracker.trackEvent)('import_validate_sql_command_failure', {
      is_import: isImport,
      error: errorSummary
    });
    return process.exit(1);
  }

  console.log('** Your database file looks good 🎉 **\n');
  await (0, _tracker.trackEvent)('import_validate_sql_command_success', {
    is_import: isImport
  });

  if (isImport) {
    // Add a confirmation step before running the import
    const yes = await (0, _prompt.confirm)([], 'Are you sure you want to continue with the import?'); // Bail if user does not wish to proceed

    if (!yes) {
      console.log(`${_chalk.default.red('Exiting')}`);
      await (0, _tracker.trackEvent)('import_continue_cancelled', {
        is_import: isImport,
        import_file: filename
      });
      process.exit();
    }

    console.log(`\n${_chalk.default.underline('Starting the import process...')}`);
    return;
  }

  console.log('\n🎉 You can now submit for import, see here for more details: ' + 'https://docs.wpvip.com/how-tos/prepare-for-site-launch/migrate-content-databases/');
};

exports.postValidation = postValidation;

const perLineValidations = line => {
  if (lineNum % 500 === 0) {
    (0, _singleLineLog.stdout)(`Reading line ${lineNum} `);
  }

  const checkValues = Object.values(checks);
  checkValues.forEach(check => {
    const results = line.match(check.matcher);

    if (results) {
      check.results.push(check.matchHandler(lineNum, results));
    }
  });
  lineNum += 1;
};

const staticSqlValidations = {
  execute: line => {
    perLineValidations(line);
  },
  postLineExecutionProcessing: async ({
    fileName,
    isImport
  }) => {
    await postValidation(fileName, isImport);
  }
};
exports.staticSqlValidations = staticSqlValidations;

const validate = async (filename, isImport = false) => {
  const readInterface = await (0, _lineByLine.getReadInterface)(filename);
  readInterface.on('line', line => {
    staticSqlValidations.execute(line);
  }); // Block until the processing completes

  await new Promise(resolve => readInterface.on('close', resolve));
  readInterface.close();
  await staticSqlValidations.postLineExecutionProcessing({
    filename,
    isImport
  });
};

exports.validate = validate;