import fs from 'fs'
import rimraf from 'rimraf'
import path from 'path'
import ZephyrService from '../../services/zephyr-service.js'
import JiraService from '../../services/jira-service.js'
import utils from './publisher-utils.js'

export default class ZephyrPublisher {

    constructor( config ) {
        this.fs = fs;
        this.rimraf = rimraf;
        this.path = path;
        this.log = null;
        this.utils = utils;
        this.zephyr = new ZephyrService(config);
        this.jira = new JiraService(config);
        this.config = config;
    }

    async publish(reportFilePath) {
      try {
          let zephyrPublisher = this;
          let logStr = zephyrPublisher.fs.readFileSync(reportFilePath, 'utf8');
          if (!logStr){
              throw new Error('Could not read logfile');
          }
          zephyrPublisher.log = JSON.parse(logStr);
          if (!zephyrPublisher.log.allResults.meta || !zephyrPublisher.log.allResults.meta.env){
              throw new Error('Logfile is missing data');
          }
          let startTime = zephyrPublisher.utils.getDateAndTime(new Date(zephyrPublisher.log.allResults.start));
          let endTime = zephyrPublisher.utils.getDateAndTime(new Date(zephyrPublisher.log.allResults.end));
          let cyclename = zephyrPublisher.log.allResults.meta.env + ' ' + startTime;
          await zephyrPublisher.zephyr.createCycle(zephyrPublisher.log.allResults.meta.testedVersion, cyclename, zephyrPublisher.log.allResults.meta.env,
            startTime, endTime);

          let publishPromises = [];
          let temproot = zephyrPublisher.path.join(zephyrPublisher.config.reportDir, 'temp');
          if (!zephyrPublisher.fs.existsSync(temproot)){
            zephyrPublisher.fs.mkdirSync(temproot);
          }
          zephyrPublisher.log.allResults.describes.forEach(describe => {
              publishPromises.push(new Promise(async (resolve) => {
                  let tempfolder = zephyrPublisher.path.join(temproot, describe.meta.uuid);
                  if (!zephyrPublisher.fs.existsSync(tempfolder)){
                      zephyrPublisher.fs.mkdirSync(tempfolder);
                  }
                  await zephyrPublisher.processLog(describe, tempfolder);
                  zephyrPublisher.rimraf.sync(tempfolder);
                  resolve();
              }));
          });
          await Promise.all(publishPromises).then(() => {
            let executionLink = zephyrPublisher.config.baseUrl + '/secure/enav/\#\?' +
            'query\=project\%20\%3D\%20\%22' + zephyrPublisher.config.projectKey +
            '\%22\%20AND\%20fixVersion\%20\%3D\%20\%22' + zephyrPublisher.log.allResults.meta.testedVersion +
            '\%22\%20AND\%20cycleName\%20in\%20\(\%22' +
            encodeURI(cyclename) + '\%22\)';
            zephyrPublisher.log.allResults['executionLink'] = executionLink
            if (zephyrPublisher.log.groupedResults){
              let groups = Object.keys(this.log.groupedResults);
              groups.forEach(group => {
                zephyrPublisher.log.groupedResults[group]['executionLink'] = executionLink;
              });
            }

            zephyrPublisher.fs.writeFileSync(reportFilePath,
              JSON.stringify(zephyrPublisher.log,null,2), function(err) {
                if (err) {
                  return console.error("Error writing updated logfile in ZephyrPublisher: " + err);
                }
            });
          });

      //     if (zephyrPublisher.config.deleteOldReports && zephyrPublisher.config.keepMonthsHistoryNbr) {
      //         let versionId = await zephyrPublisher.jira.getVersionId(zephyrPublisher.log.allResults.meta.testedVersion);
      //         let cycles = await zephyrPublisher.zephyr.getCycles(versionId);
      //         let someMonthsAgo = new Date();
      //         someMonthsAgo.setMonth(someMonthsAgo.getMonth() - zephyrPublisher.config.keepMonthsHistoryNbr);
      //         await zephyrPublisher.asyncForEach(Object.keys(cycles), async function process(cycle_key) {
      //             let cycleCreatedDate = new Date(cycles[cycle_key]["createdDate"]);
      //             if (+someMonthsAgo > +cycleCreatedDate) {
      //                 await zephyrPublisher.zephyr.deleteCycle(cycle_key);
      //             }
      //         });
      //     }

      } catch (error) {
          console.error('An error occured in ZephyrPublisher.publish, error:' + error);
          return;
      }
    }

    async processLog(describe, tempfolder){
      try {
        let zephyrPublisher = this;
        if (describe.meta && describe.meta.zephyrKey && describe.meta.zephyrKey !== '' && !isNaN(Number(describe.meta.zephyrKey.split('-')[1]))) {
          let short_comment = describe.title;
          short_comment += "\r\nLOGS:";
          let extended_comment = short_comment;
          let executionId = await zephyrPublisher.zephyr.createExecution(describe.meta.zephyrKey);
          describe.executionLink = zephyrPublisher.config.baseUrl + '/secure/enav/#/' + executionId;
          let testResult;
          let status = '7';
          let index = 1;
          let screenshots = [];
          await zephyrPublisher.asyncForEach(describe.tests, async function process(test) {
              testResult = await zephyrPublisher.processSpecLog(test, executionId);
              if (status !== testResult.status && status !== '2') {
                  if (testResult.status === '2') {
                      status = '2';
                  } else if (testResult.status === '1') {
                      status = '1';
                  } else if (status === '7' && testResult.status === '6'){
                      status = '6';
                  }
              }
              short_comment += "\r\n\t" + index + ': ' + testResult.short_comment;
              extended_comment += "\r\n\t" + index + ': ' + testResult.extended_comment;
              if (testResult.screenshots.length > 0) {
                  Array.prototype.push.apply(screenshots ,testResult.screenshots);
              }
              index++;
            });
            let logFilepath = zephyrPublisher.path.join(tempfolder, 'execution_log.txt');
            zephyrPublisher.fs.writeFileSync(logFilepath, extended_comment);
            await zephyrPublisher.zephyr.addExecutionAttachment(executionId, logFilepath);
            await zephyrPublisher.asyncForEach(screenshots, async function process(screenshot) {
                await zephyrPublisher.zephyr.addExecutionAttachment(executionId, screenshot);
            });
            await zephyrPublisher.zephyr.updateExecution(executionId, status, short_comment);
          }
        } catch (error) {
            console.error('Error processing describe log in zephyr publisher ' + describe.description  + ' error: ' + error);
            return null;
        }
    }

    async processSpecLog(speclog, executionId){
        try {
          let zephyrPublisher = this;
          let short_comment = speclog.title;
          let extended_comment;
          let specStatus;
          let screenshots = [];
          switch (speclog.state) {
              case 'passed':
                  specStatus = '1';
                  short_comment += ': PASSED';
                  break;
              case 'failed':
                  specStatus = '2';
                  short_comment += ': FAILED';
                  break;
              case 'pending':
                  specStatus = '6';
                  short_comment += ': PENDING';
                  break;
              case 'disabled':
                  specStatus = '6';
                  short_comment += ': DISABLED';
                  break;
              default:
                  short_comment += ': UNEXECUTED';
                  specStatus = '7';
                  break;
          }
          if(speclog.meta.zephyrStep && (speclog.meta.zephyrStep !== '') && !isNaN(Number(speclog.meta.zephyrStep))) {
              let stepExecutionId = await zephyrPublisher.zephyr.getExecutionStepId(executionId, speclog.meta.zephyrStep);
              await zephyrPublisher.zephyr.updateExecutionTestStep(stepExecutionId, specStatus, short_comment);
              if (speclog.screenshots) {
                await zephyrPublisher.asyncForEach(speclog.screenshots, async function processScreenshot(screenshot) {
                  await zephyrPublisher.zephyr.addStepAttachment(stepExecutionId, screenshot);
                });
              }
          } else if (speclog.screenshots) {
            Array.prototype.push.apply(screenshots, speclog.screenshots);
          }
          extended_comment = short_comment;
          if (speclog.errors) {
              extended_comment += "\r\n\t\tFailures:";
              speclog.errors.forEach(error => {
                  extended_comment += "\r\n\t\t\t" + error.type + ': ' + error.message.replace(/\n/g, '\r\n\t\t');
              });
          }
          if (speclog.browserlog && speclog.browserlog.length > 0) {
              extended_comment += "\r\n\t\tBrowserLog:";
              speclog.browserlog.forEach(browserlogItem => {
                  extended_comment +=
                    "\r\n\t\t\tTIME: " + zephyrPublisher.utils.getDateAndTime(new Date(browserlogItem.timestamp), true) +
                    ' LEVEL: ' + browserlogItem.level +
                    ' MESSAGE: ' + browserlogItem.message.replace(/\n/g, '\r\n\t\t');
              });
          }

          return {'status': specStatus, 'short_comment': short_comment, 'extended_comment': extended_comment, 'screenshots': screenshots};
      } catch (error) {
          console.log('Error processing spec log in zephyr publisher ' + speclog.title  + ' error: ' + error);
          throw error;
      }
    }

    async asyncForEach(array, callback ) {
        for (let index = 0; index < array.length; index++) {
            await callback(array[index], index, array);
        }
    }


}
