import { AfterViewInit, Component, Inject, OnInit } from '@angular/core';
import {
  FormControl,
  FormGroup,
  Validators,
  FormsModule,
  FormBuilder,
} from '@angular/forms';

import { CheckBoxSelectionService } from '@syncfusion/ej2-angular-dropdowns';
import { MatSnackBar } from '@angular/material/snack-bar';
import { WorkflowService } from 'src/app/services/samwf/workflow.service';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { FormArray } from '@angular/forms';
import { lastValueFrom, map } from 'rxjs';
import { ResponseData } from 'src/app/interfaces/response-data';
import { ResourcesService } from 'src/app/services/resources/resources.service';

@Component({
  selector: 'app-workflow-pasos-form',
  templateUrl: './workflow-pasos-form.component.html',
  styleUrls: ['./workflow-pasos-form.component.css'],
  providers: [CheckBoxSelectionService],
})
export class WorkflowPasosFormComponent implements AfterViewInit {
  formGroup: FormGroup;
  showConditionals: boolean = false;
  position = 0;
  id_workflow: any;

  workflowObject: any = {};
  workflowTasks: any[] = [];
  tasksData: any[] = [];
  action: string = '';
  data: any;
  tasks_bd: any[] = [];
  valueConditionalsArray: any[] = [];

  newSequenceCalculate: any = 0;
  nextSecuenceFlag: number = 0;
  sequenceFlag: number = 0;
  indexPositionAux = 0;

  stores = [
    { id: 0, name: 'Juan Alvarez' },
    { id: 1, name: 'Alan Carranza' },
    { id: 2, name: 'Jean Benitez' },
    { id: 4, name: 'Emmanuel Estrada' },
  ];
  arrayLettersForLevel = ['B', 'C', 'D', 'E', 'F', 'G'];

  formFields: any[] = [];

  // ---- SmartPage ----
  public btnSmall: boolean = false;
  public card_size = 'card-size-normal mat-elevation-z8';

  constructor(
    private _snackBar: MatSnackBar,
    private _samwfService: WorkflowService,
    private activatedRoute: ActivatedRoute,
    private translate: TranslateService,
    private fb: FormBuilder,
    private router: Router,
    private routerNavigate: Router,
    private _resourceService: ResourcesService
  ) {
    this.id_workflow = this.activatedRoute.snapshot.paramMap.get('id');
    activatedRoute.params.subscribe((params) => {
      this.action = params['action'];
      this.data = JSON.parse(params['data']);
    });
    translate.setDefaultLang('es');
    this.tasksData = this._samwfService.getArray();

    this.formGroup = this.createFormGroup();
  }

  ngOnInit(): void {
    this.getTasksWorkflow();
  }

  ngAfterViewInit() {
    if (window.innerWidth <= 721) {
      this.btnSmall = true;
      this.card_size = 'card-size-small';
    } else if (window.innerWidth > 721) {
      this.btnSmall = false;
      this.card_size = 'card-size-normal mat-elevation-z8';
    }
  }

  createFormGroup() {
    return (this.formGroup = this.fb.group({
      id: new FormControl(''),
      tasks: new FormControl('', Validators.required),
      positionSteps: new FormControl('', Validators.required),
      positionRequired: new FormControl(this.position),
      conditionals: this.fb.array([]),
    }));
  }

  deleteConditional(indice: number) {
    this.conditionals.removeAt(indice);
  }

  ////////////////////////////////// REGISTRAR ////////////////////////////
  async transformData(task: any) {
    let arrDinamic: any[] = [];
    this.calculoSecuenciaTareaPrincipal();
    let sequenceStop = 0;
    console.log(this.calculoSecuenciaTareaPrincipal());
    console.log(this.newSequenceCalculate);

    if (task.conditionals.length > 0 && this.newSequenceCalculate != null) {
      // si tiene condicional aplicar un clicado de las condicionales presentes y llenar la nueva secuencia, nextSequence y changeSequence
      for (let index = 0; index < task.conditionals.length; index++) {
        if (index == 0) {
          task.conditionals[index].conditionalYes.sequence =
            this.getSequenceConditional(
              this.sequenceFlag,
              this.nextSecuenceFlag
            );

          task.conditionals[index].conditionalNo.sequence =
            this.getSequenceConditional(
              this.sequenceFlag,
              this.nextSecuenceFlag
            );
          sequenceStop = task.conditionals[index].conditionalNo.sequence;
          arrDinamic.push(JSON.stringify(task.conditionals[index]));
        } else {
          //pendiente de acomodar
          if (
            task.conditionals[index].indexPosition ==
            task.conditionals[index - 1].indexYes
          ) {
            task.conditionals[index].conditionalYes.sequence =
              this.getSequenceConditional(
                task.conditionals[index - 1].conditionalYes.sequence,
                task.conditionals[index - 1].conditionalNo.sequence
              );

            task.conditionals[index].conditionalNo.sequence =
              this.getSequenceConditional(
                task.conditionals[index].conditionalYes.sequence,
                task.conditionals[index - 1].conditionalNo.sequence
              );

            arrDinamic.push(JSON.stringify(task.conditionals[index]));
          } else if (
            task.conditionals[index].indexPosition ==
            task.conditionals[index - 1].indexNo
          ) {
            task.conditionals[index].conditionalYes.sequence =
              this.getSequenceConditional(
                task.conditionals[index - 1].conditionalNo.sequence,
                this.nextSecuenceFlag
              );

            task.conditionals[index].conditionalNo.sequence =
              this.getSequenceConditional(
                task.conditionals[index].conditionalYes.sequence,
                this.nextSecuenceFlag
              );
            arrDinamic.push(JSON.stringify(task.conditionals[index]));
          }
        }
      }
      this.conditionalsFormat(arrDinamic, task.tasks);
    } else if (this.newSequenceCalculate != null) {
      this.registerOneTask(task);
    }
  }

  private conditionalsFormat(conditionalsJson: any, principalTask: any) {
    let arrTransform: any[] = [];
    let arrFormat: any[] = [];

    for (let index = 0; index < conditionalsJson.length; index++) {
      arrTransform.push(JSON.parse(conditionalsJson[index]));
    }
    for (let index = 0; index < arrTransform.length; index++) {
      if (index == 0) {
        if (arrTransform.length < 2) {
          arrTransform[index].conditionalYes.nextSequence =
            this.nextSecuenceFlag;

          arrFormat.push(arrTransform[index].conditionalYes);

          arrTransform[index].conditionalNo.changeSequence =
            arrTransform[index].conditionalNo.isConditional == true
              ? this.nextSecuenceFlag
              : null;

          arrFormat.push(arrTransform[index].conditionalNo);
        }
      } else {
        //pendiente de acomodar
        // Si la posicion actual del arreglo tiene el mismo nivel que la tarea anterior
        // Se añade a la anterior la referencia a la nueva tarea por medio del nextSequence y changeSequence en caso de ser el camino negativo

        if (
          arrTransform[index].indexPosition ==
            arrTransform[index - 1].indexYes &&
          arrTransform.length >= 2
        ) {
          arrTransform[index - 1].conditionalYes.nextSequence =
            arrTransform[index].conditionalYes.sequence;

          arrTransform[index - 1].conditionalYes.changeSequence =
            arrTransform[index - 1].conditionalYes.isConditional == true
              ? arrTransform[index].conditionalNo.sequence
              : null;
        } else if (
          arrTransform[index].indexPosition == arrTransform[index - 1].indexNo
        ) {
          arrTransform[index - 1].conditionalNo.nextSequence =
            arrTransform[index].conditionalYes.sequence;

          arrTransform[index - 1].conditionalNo.changeSequence =
            arrTransform[index - 1].conditionalNo.isConditional == true
              ? arrTransform[index].conditionalNo.sequence
              : null;
        }
      }
    }

    // Añadir al arreglo la informacion obtenida y separandolo por lo caminos si y no
    for (let index = 0; index < arrTransform.length; index++) {
      arrFormat.push(arrTransform[index].conditionalYes);
      arrFormat.push(arrTransform[index].conditionalNo);
    }

    arrTransform = arrTransform.filter((item, index) => {
      return arrTransform.indexOf(item) === index;
    });

    this.workflowTasks = this.workflowTasks.filter((item, index) => {
      return this.workflowTasks.indexOf(item) === index;
    });

    // Si alguna tarea no encontro coincidencias quiere decir que su camino termina en la tarea
    // Que el usuario indico como referencia en el formulario
    for (let index = 0; index < arrFormat.length; index++) {
      if (arrFormat[index].nextSequence == null) {
        arrFormat[index].nextSequence = this.nextSecuenceFlag;
      }
    }

    // Para evitar problemas de datos repetidos, a la tarea principal seleccionada
    // Se le asignan sus valores establecidos (secuencia, nextSequence y chagueSequence)
    principalTask.sequence = this.newSequenceCalculate;
    principalTask.nextSequence = arrFormat[0].sequence;
    principalTask.changeSequence = arrFormat[1].sequence;
    arrFormat.push(principalTask);

    this.registerTasks(arrFormat, principalTask.sequence);
  }

  private async registerTasks(arrCondtionals: any, principalTask: any) {
    // El arreglo workflowTasks tiene todas las tareas actuales del workflow
    // Se cicla el arreglo de tareas del formulario para asignarlas dentro del arreglo anterior

    for (let index = 0; index < arrCondtionals.length; index++) {
      this.workflowTasks.push(arrCondtionals[index]);
    }

    // Filtrar el arreglo en caso de existir tareas repetidas
    this.workflowTasks = this.workflowTasks.filter((item, index) => {
      return this.workflowTasks.indexOf(item) === index;
    });

    // Ordenar el arreglo de tareas por medio de la secuencia
    this.workflowTasks.sort((a: any, b: any) => a.sequence - b.sequence);
    console.log(this.workflowTasks);

    // Al añadir la tarea principal, la tarea anterior debe tener la nueva referencia en su nextSequence
    let positionTaskRegister = this.workflowTasks.findIndex((object: any) => {
      return object.sequence == principalTask;
    });

    this.workflowTasks[positionTaskRegister - 1].nextSequence =
      this.newSequenceCalculate;

    // Añadir las tareas al objeto del workflow en la referencia "tasks"
    this.workflowObject.tasks = this.workflowTasks;

    // Llamar al servicio para actualizar el flujo de trabajo
    this.asingTaskWorkflow();
  }

  private async registerOneTask(task: any) {
    // No aplicar filtro y solo enviarlo a registrar
    // al registrar ordenar el nuevo arreglo
    task.tasks.sequence = this.newSequenceCalculate;
    task.tasks.nextSequence = this.nextSecuenceFlag;

    // Añandir la tarea al arreglo de tareas original del workflow
    this.workflowTasks.push(task.tasks);

    // Filtrar el arreglo en caso de existir tareas repetidas
    this.workflowTasks = this.workflowTasks.filter((item, index) => {
      return this.workflowTasks.indexOf(item) === index;
    });

    // Ordenar el arreglo de tareas por medio de la secuencia
    this.workflowTasks.sort((a: any, b: any) => a.sequence - b.sequence);
    let positionTaskRegister = this.workflowTasks.findIndex((object: any) => {
      return object.sequence == task.tasks.sequence;
    });

    this.workflowTasks[positionTaskRegister - 1].nextSequence =
      this.newSequenceCalculate;
    this.workflowObject.tasks = this.workflowTasks;

    this.asingTaskWorkflow();
  }

  // Funcion para registro  de las tareas
  private async asingTaskWorkflow() {
    await lastValueFrom(
      this._samwfService.updateWorkflow(this.workflowObject, this.id_workflow)
    ).then(
      (data: ResponseData) => {
        console.log(data);
        this._snackBar.open('!Actualización de workflow exitoso!', 'Cerrar', {
          duration: 3000,
        });

        this.conditionals.clear();
        this.routerNavigate.navigate([`sam/workflow/${this.id_workflow}`]);
      },
      (error) => {
        this.getTasksWorkflow();
        this._resourceService.checkErrors(error);
      }
    );
  }

  ///////////////////////////// CALCULOS //////////////////////////////
  calculoSecuenciaTareaPrincipal() {
    // variables reutilizadas en los dos posibles casos
    let pasoAnterior: any = {};
    let secuenciaAnterior: any = 0;
    let secuenciaSiguiente = 0;
    let arrNumerosDisponibles: any[] = [];
    let pasoSiguiente: any = {};
    let secuenciaPasoRequerido: number = 0;

    if (this.action == 'Modificar') {
      this.newSequenceCalculate = this.data.sequence;
      return this.data.sequence;
    } else {
      if (this.positionRequired?.value == 1) {
        for (
          let indexFor = 0;
          indexFor < this.workflowTasks.length;
          indexFor++
        ) {
          if (
            this.workflowTasks[indexFor].sequence ==
            this.positionSteps?.value.sequence
          ) {
            if (this.workflowTasks[indexFor - 1] != null) {
              pasoAnterior = this.workflowTasks[indexFor - 1];
              secuenciaAnterior = pasoAnterior.sequence;
              secuenciaSiguiente = this.positionSteps?.value.sequence;

              for (
                let index = secuenciaAnterior;
                index <= secuenciaSiguiente;
                index++
              ) {
                if (index != secuenciaAnterior && index != secuenciaSiguiente) {
                  arrNumerosDisponibles.push(index);
                }
              }

              if (arrNumerosDisponibles.length > 0) {
                this.newSequenceCalculate = this.median(arrNumerosDisponibles);
                this.sequenceFlag = this.newSequenceCalculate;
                this.nextSecuenceFlag = secuenciaSiguiente;
              } else {
                this.newSequenceCalculate = null;
                this._snackBar.open(
                  'No puedes colocar la tarea en esta posición ',
                  'Cerrar',
                  {
                    duration: 4000,
                  }
                );
                return null;
              }
              return this.newSequenceCalculate;
            } else {
              //this.dialogRef.close();
              this.newSequenceCalculate = null;

              this._snackBar.open(
                'No puedes colocar la tarea en esta posición ',
                'Cerrar',
                {
                  duration: 4000,
                }
              );
              return null;
            }
          }
        }
      } else if (this.positionRequired?.value == 2) {
        // variables

        for (let index = 0; index < this.workflowTasks.length; index++) {
          if (
            this.workflowTasks[index].sequence ==
            this.positionSteps?.value.sequence
          ) {
            if (this.workflowTasks[index + 1] != null) {
              pasoSiguiente = this.workflowTasks[index + 1];
              secuenciaSiguiente = pasoSiguiente.sequence;
              secuenciaPasoRequerido = this.workflowTasks[index].sequence;

              for (
                let i = secuenciaPasoRequerido;
                i <= secuenciaSiguiente;
                i++
              ) {
                if (i != secuenciaPasoRequerido && i != secuenciaSiguiente) {
                  arrNumerosDisponibles.push(i);
                }
              }
              if (arrNumerosDisponibles.length > 0) {
                this.newSequenceCalculate = this.median(arrNumerosDisponibles);
                this.sequenceFlag = this.newSequenceCalculate;
                this.nextSecuenceFlag = secuenciaSiguiente;
              } else {
                this.newSequenceCalculate = null;

                this._snackBar.open(
                  'No puedes colocar la tarea en esta posición ',
                  'Cerrar',
                  {
                    duration: 4000,
                  }
                );
                return null;
              }
              return this.newSequenceCalculate;
            } else {
              this.newSequenceCalculate = null;

              this._snackBar.open(
                'No puedes colocar la tarea en esta posición ',
                'Cerrar',
                {
                  duration: 4000,
                }
              );
              return null;
            }
          }
        }
      }
    }
    return null;
  }

  getSequenceConditional(sequenceFlag: any, nexSequence: any) {
    let arrFreeNumbers: any[] = [];

    for (let index = sequenceFlag; index <= nexSequence; index++) {
      if (index != this.newSequenceCalculate && index != nexSequence) {
        arrFreeNumbers.push(index);
      }
    }

    if (arrFreeNumbers.length > 0) {
      this.sequenceFlag = this.median(arrFreeNumbers);
      return this.sequenceFlag;
    } else {
      this._snackBar.open(
        'No quedan mas tareas, intente cambiar la posicion de la tarea',
        'Cerrar',
        {
          duration: 4000,
        }
      );
      return null;
    }
  }

  median(arr: any[]) {
    arr.sort((a, b) => a - b);
    const dimension = arr.length;
    return Math.round(
      dimension % 2 == 0
        ? arr
            .slice(dimension / 2 - 1, dimension / 2 + 1)
            .reduce((a, b) => a + b) / 2
        : arr.slice(dimension / 2, dimension / 2 + 1)[0]
    );
  }

  ///////////////// CAMPOS DINAMICOS /////////////////////////////////
  verificar(itemCondicionales: any, indice: any) {
    if (itemCondicionales.isConditional) {
      this.showConditionals = true;
      this.addConditionals(itemCondicionales, indice);
    } else {
      if (indice == 'A' && itemCondicionales.isConditional == false) {
        this.conditionals.clear();
        this.indexPositionAux = 0;
      }

      this.verifyChangesTasksForm(indice);
    }
  }

  private verifyChangesTasksForm(indice: any) {
    let arrAuxConditionals: any[] = [];
    let objAuxYes = '';
    let objAuxNo = '';

    for (let index = 0; index < this.conditionals.value.length; index++) {
      if (indice == this.conditionals.value[index].indexPosition) {
        arrAuxConditionals.push(this.conditionals.value[index].indexPosition);
        objAuxYes = this.conditionals.value[index].indexYes;
        objAuxNo = this.conditionals.value[index].indexNo;
      }

      if (arrAuxConditionals.length > 0) {
        if (objAuxNo == this.conditionals.value[index].indexPosition) {
          arrAuxConditionals.push(this.conditionals.value[index].indexPosition);
          objAuxYes = this.conditionals.value[index].indexYes;
          objAuxNo = this.conditionals.value[index].indexNo;
        } else if (objAuxYes == this.conditionals.value[index].indexPosition) {
          arrAuxConditionals.push(this.conditionals.value[index].indexPosition);
          objAuxYes = this.conditionals.value[index].indexYes;
          objAuxNo = this.conditionals.value[index].indexNo;
        }
      }
    }

    if (arrAuxConditionals.length > 0) {
      for (
        let indexConditionals = 0;
        indexConditionals < this.conditionals.value.length;
        indexConditionals++
      ) {
        for (let arrAux = 0; arrAux < arrAuxConditionals.length; arrAux++) {
          if (
            this.conditionals.value[indexConditionals].indexPosition ==
            arrAuxConditionals[arrAux]
          ) {
            this.conditionals.removeAt(indexConditionals);
          }
        }
      }

      this.showConditionals = false;
    }
  }

  verificarPosicion(itemPosicion: any) {
    this.position = itemPosicion;
  }

  addConditionals(taskCurrent: any, indice: any) {
    if (this.conditionals.value.length == 0) {
      const conditionalsAux = this.fb.group({
        conditionalYes: new FormControl(''),
        conditionalNo: new FormControl(''),
        taskCurrent: new FormControl(taskCurrent),
        indexYes: new FormControl(
          this.arrayLettersForLevel[this.indexPositionAux] + 1
        ),
        indexNo: new FormControl(
          this.arrayLettersForLevel[this.indexPositionAux] + 2
        ),
        indexPosition: new FormControl('A'),
      });
      this.conditionals.push(conditionalsAux);
      this.indexPositionAux++;
    } else {
      if (this.conditionals.value.length <= 2) {
        let position = this.conditionals.value.findIndex(
          (object: any) => object.indexPosition == indice
        );

        const conditionals = this.fb.group({
          conditionalYes: new FormControl(''),
          conditionalNo: new FormControl(''),
          taskCurrent: new FormControl(taskCurrent),
          indexPosition: new FormControl(indice),
          indexYes: new FormControl(
            this.arrayLettersForLevel[this.indexPositionAux] + '1'
          ),
          indexNo: new FormControl(
            this.arrayLettersForLevel[this.indexPositionAux] + '2'
          ),
        });

        if (position <= -1) {
          this.conditionals.push(conditionals);
          let arr = this.conditionals.value.sort(function (
            indice1: any,
            indice2: any
          ) {
            return indice1.indexPosition.localeCompare(indice2.indexPosition);
          });
          this.conditionals.setValue(arr);
          this.indexPositionAux++;
        }
      } else {
        this._snackBar.open('Alcanzo el maximo de condicionales', 'Cerrar', {
          duration: 3000,
        });
      }
    }
  }

  ////////////// CONSULTAS /////////////////////////////////////////
  private async getTasksWorkflow() {
    await lastValueFrom(this._samwfService.getWorkflow(this.id_workflow)).then(
      async (data: any) => {
        this.workflowObject = data.response;

        /* this.workflowTasks = data.tasks.filter(
          (object: any) => object.id != false
        ); */
        this.workflowTasks = data.response.tasks;
        console.log(data.response.tasks);
      },
      (error: any) => {
        this._resourceService.checkErrors(error);
      }
    );
  }

  backToWorkflows() {
    this.routerNavigate.navigate([`sam/workflow/${this.id_workflow}`]);
  }

  public onResize(event: any) {
    if (event.target.innerWidth <= 721) {
      this.btnSmall = true;
      this.card_size = 'card-size-small';
    } else if (event.target.innerWidth > 721) {
      this.btnSmall = false;
      this.card_size = 'card-size-normal mat-elevation-z8';
    }
  }

  get tasks() {
    return this.formGroup.get('tasks');
  }

  get notification() {
    return this.formGroup.get('notification');
  }

  get conditionals(): FormArray {
    return this.formGroup.get('conditionals') as FormArray;
  }

  get sequence() {
    return this.formGroup.get('sequence');
  }

  get positionSteps() {
    return this.formGroup.get('positionSteps');
  }

  get positionRequired() {
    return this.formGroup.get('positionRequired');
  }

  get employees() {
    return this.formGroup.get('employees');
  }

  get employeesNotification() {
    return this.formGroup.get('employeesNotification');
  }

  get taskCurrent() {
    return this.formGroup.get('taskCurrent');
  }
}
