// this file contains code to create commits in a consistent way

import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js';

export const run = async (argvArg: any) => {
  if (argvArg.format) {
    const formatMod = await import('../mod_format/index.js');
    await formatMod.run();
  }


  logger.log('info', `gathering facts...`);
  const aidoc = new plugins.tsdoc.AiDoc();
  await aidoc.start();

  const nextCommitObject = await aidoc.buildNextCommitObject(paths.cwd);

  logger.log('info', `---------
    Next recommended commit would be:
    ===========
    -> ${nextCommitObject.recommendedNextVersion}:
    -> ${nextCommitObject.recommendedNextVersionLevel}(${nextCommitObject.recommendedNextVersionScope}): ${nextCommitObject.recommendedNextVersionMessage}
    ===========
  `);
  const commitInteract = new plugins.smartinteract.SmartInteract();
  commitInteract.addQuestions([
    {
      type: 'list',
      name: `commitType`,
      message: `Choose TYPE of the commit:`,
      choices: [`fix`, `feat`, `BREAKING CHANGE`],
      default: nextCommitObject.recommendedNextVersionLevel,
    },
    {
      type: 'input',
      name: `commitScope`,
      message: `What is the SCOPE of the commit:`,
      default: nextCommitObject.recommendedNextVersionScope,
    },
    {
      type: `input`,
      name: `commitDescription`,
      message: `What is the DESCRIPTION of the commit?`,
      default: nextCommitObject.recommendedNextVersionMessage,
    },
    {
      type: 'confirm',
      name: `pushToOrigin`,
      message: `Do you want to push this version now?`,
      default: true,
    },
  ]);
  const answerBucket = await commitInteract.runQueue();
  const commitString = createCommitStringFromAnswerBucket(answerBucket);
  const commitVersionType = (() => {
    switch (answerBucket.getAnswerFor('commitType')) {
      case 'fix':
        return 'patch';
      case 'feat':
        return 'minor';
      case 'BREAKING CHANGE':
        return 'major';
    }
  })();

  logger.log('info', `OK! Creating commit with message '${commitString}'`);
  const smartshellInstance = new plugins.smartshell.Smartshell({
    executor: 'bash',
    sourceFilePaths: [],
  });

  logger.log('info', `Baking commitinfo into code ...`);
  const commitInfo = new plugins.commitinfo.CommitInfo(paths.cwd, commitVersionType);
  await commitInfo.writeIntoPotentialDirs();

  logger.log('info', `Writing changelog.md ...`);
  let changelog = nextCommitObject.changelog;
  changelog = changelog.replaceAll('{{nextVersion}}', (await commitInfo.getNextPlannedVersion()).versionString);
  changelog = changelog.replaceAll('{{nextVersionScope}}', `${await answerBucket.getAnswerFor('commitType')}(${await answerBucket.getAnswerFor('commitScope')})`);
  changelog = changelog.replaceAll('{{nextVersionMessage}}', nextCommitObject.recommendedNextVersionMessage);
  if (nextCommitObject.recommendedNextVersionDetails?.length > 0) {
    changelog = changelog.replaceAll('{{nextVersionDetails}}', '- ' + nextCommitObject.recommendedNextVersionDetails.join('\n- '));
  } else {
    changelog = changelog.replaceAll('\n{{nextVersionDetails}}', '');
  }

  await plugins.smartfile.memory.toFs(changelog, plugins.path.join(paths.cwd, `changelog.md`));

  logger.log('info', `Staging files for commit:`);
  await smartshellInstance.exec(`git add -A`);
  await smartshellInstance.exec(`git commit -m "${commitString}"`);
  await smartshellInstance.exec(`npm version ${commitVersionType}`);
  if (answerBucket.getAnswerFor('pushToOrigin') && !(process.env.CI === 'true')) {
    await smartshellInstance.exec(`git push origin master --follow-tags`);
  }
};

const createCommitStringFromAnswerBucket = (answerBucket: plugins.smartinteract.AnswerBucket) => {
  const commitType = answerBucket.getAnswerFor('commitType');
  const commitScope = answerBucket.getAnswerFor('commitScope');
  const commitDescription = answerBucket.getAnswerFor('commitDescription');
  return `${commitType}(${commitScope}): ${commitDescription}`;
};