import { Component, Watch } from 'vue-property-decorator';
import get from 'lodash/get';
import has from 'lodash/has';
import find from 'lodash/find';
import assign from 'lodash/assign';
import findIndex from 'lodash/findIndex';
import Loadable from '@mixins/Loadable';
import {
  WorkflowServiceApi,
  TaskHistoryEntry,
  UserTaskDefinition,
  UserTaskListItem,
} from '@openapi/wf';

const wfApi = new WorkflowServiceApi();

interface HistoryElement extends TaskHistoryEntry {
  inputData: unknown;
  isReadonly: boolean;
}

@Component({})
export default class StepperComponent extends Loadable {
  loading = false;

  definitions: UserTaskDefinition[] = [];
  history: TaskHistoryEntry[] = [];

  private currentStepId: string | null = null;

  private taskList: UserTaskListItem[] = [];

  private form = '';

  private isFormByStepReadOnly(step: any): boolean {
    const defId: string | null = this.task?.userTask?.defId || null;
    const isCurrentTask: boolean = defId === step.taskDefKey;

    let result: boolean = has(
      {
        step,
      },
      'step.submitEntry'
    );

    if (isCurrentTask) {
      const taskId: string | null = this.task?.userTask?.taskId || null;

      result = taskId !== this.taskId;
    }

    return result;
  }

  private get task(): any | null {
    return (
      find(this.taskList, (item: UserTaskListItem) => {
        const taskId: string | null = item.userTask?.taskId || null;

        return taskId === this.taskId;
      }) || null
    );
  }

  private get procDefId(): string | undefined {
    return this.task?.userTask?.procDefId;
  }

  private get title(): string | null {
    return this.task?.process?.title || null;
  }

  private getFormByStepInputData(step: any): any {
    let data: any = JSON.parse(
      get(
        {
          step,
        },
        'step.submitEntry.data',
        '{}'
      )
    );

    if (this.task && this.task.userTask.defId === this.currentStepId) {
      const processName: string | null = this.task?.process?.defKey || null;
      const userTaskId: string | null = this.taskId;

      data = {
        processName,
        userTaskId,
      };

      if (this.task?.userTask?.outData) {
        assign(data, this.task.userTask.outData);
      }
    }

    return data;
  }

  submit(e: Event, data: any) {
    if (this.taskId) {
      return this.loadingUntilPromiseResolved(
        wfApi.submitForm(this.taskId, data)
      );
    }
  }

  private get historyCast(): any[] {
    const defId: string | null = this.task?.userTask?.defId || null;
    const index: number = findIndex(
      this.definitions,
      (el: any) => el.taskDefId === defId
    );

    const historyCastArray: HistoryElement[] = [];

    historyCastArray.push(
      ...this.history.map((historyElement) => {
        return {
          ...historyElement,
          inputData: this.getFormByStepInputData(historyElement),
          isReadonly: this.isFormByStepReadOnly(historyElement),
        };
      })
    );

    historyCastArray.push(
      ...this.definitions.slice(index + 1).map((el: any) => {
        return {
          ...el,
          disable: true,
          taskDefKey: `${el.taskDefId}-disable`,
          inputData: this.getFormByStepInputData(el),
          isReadonly: this.isFormByStepReadOnly(el),
        };
      })
    );

    return historyCastArray;
  }

  private async init() {
    this.loading = true;
    const assignee = this.$store.getters['oidcClient/currentUser'].sub;

    try {
      const {
        data: { tasks: list = [] },
      } = await wfApi.taskList(
        'true',
        undefined,
        undefined,
        undefined,
        assignee,
        this.traceId
      );
      this.taskList = list;

      const {
        data: { tasksDefinitions: definitions = [] },
      } = await wfApi.getTaskDefList(this.traceId, this.procDefId);
      this.definitions = definitions;

      // this.definitions.splice(3, 0, {
      //   taskDefId: 'EmployeesPasswordUrlFormTask',
      //   title: 'createPasswordProcess.title',
      //   formKey: 'EmployeesPasswordUrlForm',
      //   data: 'createPassword',
      //   stepNum: '2.2',
      //   transitions: [
      //     {
      //       id: 'SequenceFlow_1fcite0',
      //     },
      //   ],
      // });

      ({ data: this.history } = await wfApi.getTaskHistory(this.traceId));

      this.loading = false;
      this.currentStepId = this.task?.userTask?.defId || null;
    } catch (e) {
      console.error('[base-stepper][init] failed', e);
      this.loading = false;
    }
  }

  private initForm(): Promise<void> {
    return new Promise((resolve, reject) => {
      const task: any | null =
        find(this.history, (el: any) => el.taskDefKey === this.currentStepId) ||
        null;
      const formKey: string | null = task?.formKey || null;

      if (formKey) {
        this.form = this.$GlobalComponentImporter.registerComponent(
          formKey,
          'forms/'
        );
        resolve();
      } else {
        return reject();
      }
    });
  }

  @Watch('taskId', {
    immediate: true,
  })
  private taskIdHandler(): void {
    this.init();
  }

  @Watch('currentStepId', {
    immediate: true,
  })
  private currentStepIdHandler(): void {
    this.loading = true;

    this.initForm().finally(() => {
      this.loading = false;
    });
  }

  get traceId(): string | undefined {
    return get(
      {
        route: this.$route,
      },
      'route.params.traceId'
    )
      ? this.$route.params.traceId.toString()
      : undefined;
  }

  get taskId(): string | null {
    return get(
      {
        route: this.$route,
      },
      'route.query.taskId'
    )
      ? this.$route.query.taskId.toString()
      : null;
  }
}
