import { TestResult } from '@jest/test-result';
import { Config } from '@jest/types';
import { bold, cyan, green, grey, red, yellow } from 'chalk';

import { OTHER } from './constants';
import {
  CustomLogEntry,
  CustomLogType,
  PrepareWarnings,
  Warning,
  WarningDataArray,
} from './types';

const log = ({ message, type, origin }: CustomLogEntry): void => {
  const colors = {
    warn: yellow,
    error: red,
    log: grey,
    debug: cyan,
  };

  if (Object.values(CustomLogType).includes(type)) {
    console[type](colors[type](message));
    console[type](origin);
  }
};

const formatResult = (status: string, title: string): string =>
  status === 'failed'
    ? bold(red(`${status.toUpperCase()} - ${title}`))
    : green(`${status.toUpperCase()} - ${title}`);

const getFileName = (filePath: string): string => {
  const filePathAsArray = filePath.split('/');

  return filePathAsArray[filePathAsArray.length - 1].split('.')[0];
};

const convertToSeconds = (milliseconds: number) => milliseconds / 1000;

const omitWarningsData = (
  globalConfig: Config.InitialOptions,
): boolean | undefined => globalConfig.verbose || globalConfig.silent;

const prepareWarningRow = (
  acc: WarningDataArray,
  curr: Array<string | number>,
) => {
  const warningRow = [` > ${curr[0]}`, curr[1], ''];

  acc.push(warningRow);

  return acc;
};

const prepareWarnings: PrepareWarnings = (warningsPerTest) =>
  Object.entries(warningsPerTest)
    .sort((a, b) => {
      if (a[0] === OTHER) return 1;
      if (b[0] === OTHER) return -1;

      return b[1] - a[1];
    })
    .reduce(prepareWarningRow, []);

const addFilesSetToWarningConfig = (config: Warning): Warning => ({
  ...config,
  files: new Set(),
});

const isHighlighted = (limit: number, testDuration?: number) =>
  testDuration ? testDuration > limit : false;

const prepareTableRow = (
  testResult: TestResult,
  limit: number,
  globalConfig: Config.InitialOptions,
): Array<string | number> => {
  const { testFilePath, console, perfStats } = testResult;
  const filePath = testFilePath.split('/').slice(-1);
  const numberOfWarnings = console ? console.length : 0;
  const testDuration = isHighlighted(limit, perfStats.runtime)
    ? red(`${convertToSeconds(perfStats.runtime)}`)
    : convertToSeconds(perfStats.runtime);

  return omitWarningsData(globalConfig)
    ? [`${filePath}`, `${testDuration}s`]
    : [`${filePath}`, `${numberOfWarnings}`, `${testDuration}s`];
};

const prepareGreetingMessage = (numTotalTestSuites: number): string =>
  cyan(`\nRunning ${numTotalTestSuites} test suites, quietly for speed 🏎️ `);

export {
  addFilesSetToWarningConfig,
  formatResult,
  getFileName,
  log,
  omitWarningsData,
  prepareGreetingMessage,
  prepareTableRow,
  prepareWarnings,
};
