import {injectable, inject} from 'inversify';
import {EtlFlow} from 'etl-typings';
import {PostalAgent} from '../interfaces/postal-agent';
import {ForceErrorImpl, IPostal, CommandUtil} from 'firmament-yargs';
import {ProcessFileWithFlowOptions, FullPipeline, ProcessFullPipelineStatus} from '../interfaces/vita-options-results';
import {VitaTasks} from '../interfaces/vita-tasks';
import kernel from "../inversify.config";

const path = require('path');

@injectable()
export class PostalAgentImpl extends ForceErrorImpl implements PostalAgent {
  constructor(@inject('IPostal') private postal: IPostal,
              @inject('CommandUtil') private commandUtil: CommandUtil,
              @inject('VitaTasks') private vitaTasks: VitaTasks) {
    super();
    let me = this;
    me.postal.subscribe({
      channel: 'FirmamentVita',
      topic: 'ProcessFileWithFlow',
      callback: (ppfwf: ProcessFileWithFlowOptions) => {
        ppfwf.etlFile.addFlows([{name: ppfwf.flowName}], (err, etlFlows: EtlFlow[]) => {
          if (me.commandUtil.logError(err)
            || !etlFlows
            || etlFlows.length != 1) {
            return;
          }
          //We've got the flow, now fire up the VitaTask
          let etlFlow = etlFlows[0];
          etlFlow.addSteps([
            {
              name: 'decryptAndUnTar',
              index: 0
            },
            {
              name: 'unZipFile',
              index: 1
            },
            {
              name: 'mergePcap',
              index: 2
            }
          ], (err, etlSteps) => {
            if (me.commandUtil.logError(err)
              || !etlSteps
              || etlSteps.length != 3) {
              return;
            }
            etlFlow.loadEntireObject((err, etlFlow: EtlFlow) => {
              let fullPipeline = kernel.get<FullPipeline>('FullPipeline');
              fullPipeline.decryptAndUnTarOptions.encryptedFiles = [path.resolve(ppfwf.etlFile.path, ppfwf.etlFile.name)];
              fullPipeline.decryptAndUnTarOptions.password = ppfwf.fileEncryptionPassword;

              etlFlow.currentStepIndex = Number.MAX_SAFE_INTEGER;

              vitaTasks.processFullPipelineInstance(
                fullPipeline,
                (err, status: ProcessFullPipelineStatus) => {
                  if (status.mergePcapFilesStatus && etlFlow.currentStepIndex !== 2) {
                    etlFlow.currentStepIndex = 2;
                    etlFlow.steps[etlFlow.currentStepIndex].startTime =
                      etlFlow.steps[etlFlow.currentStepIndex - 1].endTime = new Date();
                  }
                  else if (status.unZipFileStatus && etlFlow.currentStepIndex !== 1) {
                    etlFlow.currentStepIndex = 1;
                    etlFlow.steps[etlFlow.currentStepIndex].startTime =
                      etlFlow.steps[etlFlow.currentStepIndex - 1].endTime = new Date();
                  }
                  else if (status.decryptAndUnTarStatus && etlFlow.currentStepIndex !== 0) {
                    etlFlow.currentStepIndex = 0;
                    etlFlow.steps[etlFlow.currentStepIndex].startTime = new Date();
                  }
                  switch (etlFlow.currentStepIndex) {
                    case 0:
                      etlFlow.steps[etlFlow.currentStepIndex].progress =
                        status.decryptAndUnTarStatus.current / status.decryptAndUnTarStatus.total;
                      break;
                    case 1:
                      etlFlow.steps[etlFlow.currentStepIndex].progress =
                        status.unZipFileStatus.current / status.unZipFileStatus.total;
                      break;
                    case 2:
                      etlFlow.steps[etlFlow.currentStepIndex].progress =
                        status.mergePcapFilesStatus.current / status.mergePcapFilesStatus.total;
                      break;
                  }
                  status = status || {status: 'Running'};
                  etlFlow.steps[etlFlow.currentStepIndex].status = status.status;
                  etlFlow.steps[etlFlow.currentStepIndex].currentTime = new Date();
                  etlFlow.steps[etlFlow.currentStepIndex].writeToDb(() => {
                    me.postal.publish({
                      channel: 'FirmamentVita',
                      topic: ppfwf.operationUUID,
                      data: {err, status}
                    });
                  });
                },
                (err, result) => {
                  result = result || {status: 'Finished'};
                  me.postal.publish({
                    channel: 'FirmamentVita',
                    topic: ppfwf.operationUUID,
                    data: {err, result}
                  });
                }
              );
            });
          });
        });
      }
    });
  }
}
