import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { Component, AfterViewInit, ViewChild, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Route, Router, ActivatedRoute } from '@angular/router';
import { lastValueFrom } from 'rxjs';
import { GetbfoAddconditionComponent } from 'src/app/components/resources/dialogs/getb/getbfo/getbfo-addcondition/getbfo-addcondition.component';
import { GETBGMService } from 'src/app/services/getb/getbgm/getbgm.service';
import { GETBGTService } from 'src/app/services/getb/getbgt/getbgt.service';
import { GETBMEService } from 'src/app/services/getb/getbme/getbme.service';
import { GETBREService } from 'src/app/services/getb/getbre/getbre.service';
import { GETBSMService } from 'src/app/services/getb/getbsm/getbsm.service';
import { GETBTBService } from 'src/app/services/getb/getbtb/getbtb.service';
import { ResourcesService } from 'src/app/services/resources/resources.service';
import { SubmoduloResponse } from 'src/app/interfaces/getb/getbsb.interface';
import { HttpErrorResponse } from '@angular/common/http';
import { TableDynManagementRelationsTable } from '../table-dyn-management-form/table-dyn-management-relations-table/table-dyn-management-relations-table.component';
import { TableDynManagementAdvanceQuery } from '../table-dyn-management-form/table-dyn-management-advance-query/table-dyn-management-advance-query.component';

export interface ModuloResponse {
  CODIGO_MODULO: string;
  MODULO: string;
  ESTADO: string;
}

export interface ResponseData {
  error: boolean;
  msg: string;
  response: Array<any>;
}

@Component({
  selector: 'app-getbtb-form-edit',
  templateUrl: './table-dyn-management-form-edit.component.html',
  styleUrls: ['./table-dyn-management-form-edit.component.css'],
})
export class TableDynManagementFormEdit implements AfterViewInit {
  @ViewChild(MatPaginator) public paginator!: MatPaginator;
  @ViewChild(MatSort) public sort!: MatSort;

  public formGroupUbication: FormGroup;
  public formGroupTableDB: FormGroup;
  public formGroup: FormGroup;
  public displayedColumns: string[] = [
    'Position',
    'Name',
    'Weight',
    'Symbol',
    'Acciones',
  ];
  public dataSource: MatTableDataSource<any>;

  public arr_modulo: ModuloResponse[] = [];
  public arr_submodulo: SubmoduloResponse[] = [];
  public arr_menu: any[] = [];

  public arr_table: Array<TableData> = [];
  public arr_relationship: Array<any> = [];
  public arr_columns: any = [];

  public model: Array<any> = [];

  public arr_acciones: Array<string> = [];
  public btn_register_enable: boolean = false;
  public column_action_enable: boolean = false;
  public paginator_enable: boolean = false;
  public searcher_enable: boolean = false;

  public eliminar: boolean = false;
  public editar: boolean = false;
  public ver_info: boolean = false;
  public bloquear: boolean = false;
  public ver_docs: boolean = false;

  public step = 0;

  public data_table: Array<any> = [];

  public arr_conditions: Array<any> = [];
  public columnsConditions: string[] = ['cond1', 'ope', 'cond2', 'accion'];
  public columnsRelations: Array<any> = [];
  public arrayInners: Array<any> = [];
  public arrayInnersAuxiliar: Array<any> = [];

  dataJSON: any = {};

  public idTable: any;
  public is_advance_search: boolean = false;
  public query: string = '';
  constructor(
    public dialog: MatDialog,
    private _moduloService: GETBGMService,
    private _getbsmService: GETBSMService,
    private _getbmeService: GETBMEService,
    private _getbtbService: GETBTBService,
    private _getbreService: GETBREService,
    private _resourceService: ResourcesService,
    private _getbgtService: GETBGTService,
    private router: ActivatedRoute,
    private _router: Router
  ) {
    this.idTable = this.router.snapshot.paramMap.get('id');
    this.getDataTable();
    this.dataSource = new MatTableDataSource();
    this.formGroupUbication = this.createFormUbication();
    this.formGroupTableDB = this.createFormTableDB();
    this.formGroup = this.createForm();
  }

  ngAfterViewInit() {
    this.dataModule();
    this.dataTable();
  }

  drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.model, event.previousIndex, event.currentIndex);
  }

  private async getDataTable() {
    await lastValueFrom(this._getbtbService.getTable(this.idTable)).then(
      (data: any) => {
        if (!data.error) {
          this.table_name?.setValue(data.response.table_name);
          this.dataJSON = data.response;
          this.arrayInners = data.response.inners;
          this.arr_conditions = data.response.conditions;
          this.column_action_enable = this.checkBoxActions();
          this.is_advance_search = data.response.is_advance_search;
        }
      },
      (error: HttpErrorResponse) => this._resourceService.checkErrors(error)
    );
  }

  // Obtener módulos
  private async dataModule() {
    await lastValueFrom(this._moduloService.getModules()).then(
      (data: ResponseData) => {
        if (!data.error) this.arr_modulo = data.response;
      },
      (error: HttpErrorResponse) => this._resourceService.checkErrors(error)
    );
  }

  // Obtener tablas
  private async dataTable() {
    await lastValueFrom(this._getbgtService.getTables()).then(
      (data: any) => {
        if (!data.error) {
          this.arr_table = data.response;
          let positionMainTable = this.arr_table.findIndex((object: any) => {
            return object.NOMBRE_TABLA == this.dataJSON.tabla_principal;
          });

          this.main_table?.setValue(this.arr_table[positionMainTable]);
          this.dataRelationship();
        }
      },
      (error: HttpErrorResponse) => this._resourceService.checkErrors(error)
    );
  }

  checkBoxActions() {
    this.eliminar = this.dataJSON.acciones.eliminar;
    this.editar = this.dataJSON.acciones.editar;
    this.bloquear = this.dataJSON.acciones.bloquear;
    this.ver_docs = this.dataJSON.acciones.ver_docs;
    this.ver_info = this.dataJSON.acciones.ver_info;
    this.btn_register_enable = this.dataJSON.btn_register_enable;
    if (
      this.dataJSON.acciones.bloquear == true ||
      this.dataJSON.acciones.editar == true ||
      this.dataJSON.acciones.eliminar == true ||
      this.dataJSON.acciones.ver_docs == true ||
      this.dataJSON.acciones.ver_info == true
    ) {
      return true;
    } else {
      return false;
    }
  }

  // Obtener tablas relacionales
  public async dataRelationship() {
    await lastValueFrom(
      this._getbreService.getOneRelationship(
        this.main_table?.value.NOMBRE_TABLA
      )
    ).then(
      (data: ResponseData) => {
        if (!data.error) {
          this.arr_relationship = data.response;
          data.response.length > 0
            ? this.relation_table?.enable()
            : this.relation_table?.disable();
          this.columns?.enable();

          this.dataColumns();
        }
      },
      (error: HttpErrorResponse) => this._resourceService.checkErrors(error)
    );
  }

  // Obtener columnas
  public async dataColumns() {
    this.data_table = [];
    let aux_columns: any[] = [];

    for (let index = 0; index < this.arrayInners.length; index++) {
      aux_columns.push(this.arrayInners[index].name_table);
      aux_columns.push(this.arrayInners[index].inner_table);
    }

    let setObj: any = new Set(); // creamos pares de clave y array

    aux_columns = aux_columns.reduce((acc: any, object: any) => {
      if (!setObj.has(object.table)) {
        setObj.add(object, object);
        acc.push(object);
      }
      return acc;
    }, []);

    aux_columns.unshift(this.main_table?.value.NOMBRE_TABLA);

    await lastValueFrom(
      this._getbgtService.getColumns({ tables: aux_columns })
    ).then(
      (data: any) => {
        if (!data.error) {
          this.arr_columns = data.response;
          this.arr_columns.push('Acciones');

          let setObj: any = new Set(); // creamos pares de clave y array

          this.arr_columns = this.arr_columns.reduce(
            (acc: any, object: any) => {
              if (!setObj.has(object.table)) {
                setObj.add(object.table, object);
                acc.push(object);
              }
              return acc;
            },
            []
          );
        }
        // this.columns?.setValue(this.arr_columns[0].columns);
        this.boxesColumns();
        this.generateModel();
      },
      (error: HttpErrorResponse) => this._resourceService.checkErrors(error)
    );
  }

  boxesColumns() {
    let arrAux = this.arr_columns;
    arrAux.splice(-1, 1);

    let arrBoxes: any[] = [];
    for (let index = 0; index < arrAux.length; index++) {
      for (let indexC = 0; indexC < arrAux[index].columns.length; indexC++) {
        let positionColumn = this.dataJSON.model.findIndex((object: any) => {
          return object.column == arrAux[index].columns[indexC];
        });

        if (positionColumn > -1) {
          arrBoxes[positionColumn] = arrAux[index].columns[indexC];
        }
      }
    }

    let setObj: any = new Set(); // creamos pares de clave y array

    arrBoxes = arrBoxes.reduce((acc: any, object: any) => {
      if (!setObj.has(object)) {
        setObj.add(object, object);
        acc.push(object);
      }
      return acc;
    }, []);

    this.columns?.setValue(arrBoxes);
  }

  // Generación de NgModel para cada dato del formulario
  public generateModel() {
    this.model = [];
    this.columns?.value.map((colum: string) => {
      this.arr_columns.map((data: any) => {
        if (data !== 'Acciones') {
          data.columns.map((item: string) => {
            if (colum !== 'Acciones' && item === colum)
              this.model.push({
                new_column: '',
                column: colum,
                db: data.table,
              });
          });
        }
      });
    });

    let setObj: any = new Set(); // creamos pares de clave y array

    this.model = this.model.reduce((acc: any, object: any) => {
      if (!setObj.has(object.column)) {
        setObj.add(object.column, object);
        acc.push(object);
      }
      return acc;
    }, []);

    for (let index = 0; index < this.dataJSON.model.length; index++) {
      let position = this.model.findIndex((object: any) => {
        return (
          object.db == this.dataJSON.model[index].db &&
          object.column == this.dataJSON.model[index].column
        );
      });

      if (position > -1) {
        this.model[position].new_column =
          this.dataJSON.model[index].new_column != null
            ? this.dataJSON.model[index].new_column
            : '';
      }
    }
  }

  // Seleccionar Acciones
  public selectedActions() {
    this.data_table = [];
    let valid = this.model.filter(
      (element: any) => element.column === 'Acciones'
    );
    if (valid.length === 0)
      this.model.push({ new_column: 'Acciones', column: 'Acciones' });
  }

  // Ver los datos de la tabla
  public async viewExample() {
    let obj_res = {
      tabla_principal: this.main_table?.value,
      inners: this.arrayInners,
      conditions: this.arr_conditions,
      model: this.model,
      table_name: this.table_name?.value,
      btn_register_enable: this.btn_register_enable,
      acciones: {
        eliminar: this.eliminar,
        editar: this.editar,
        ver_info: this.ver_info,
        bloquear: this.bloquear,
        ver_docs: this.ver_docs,
      },
    };

    await lastValueFrom(this._getbtbService.getDataTable(obj_res)).then(
      (data: any) => {
        if (!data.error) this.data_table = data.response;
      },
      (error: HttpErrorResponse) => this._resourceService.checkErrors(error)
    );
  }

  // Generar datos de la tabla
  public async generateDataTable() {
    let idEnc = localStorage.getItem('idusuario');
    if (!idEnc) {
      this._resourceService.openSnackBar(
        'Ocurrio un error al momento de obtener el usuario.'
      );
    } else {
      let resultFilter = [...new Set(this.relation_table?.value)];
      this.relation_table?.setValue(resultFilter);
      let obj_res = {
        tabla_principal: this.main_table?.value,
        inners: this.arrayInners,
        conditions: this.arr_conditions,
        model: this.model,
        user: idEnc,
        query: this.query,
        is_advance_search: this.is_advance_search,
        table_name: this.table_name?.value,
        btn_register_enable: this.btn_register_enable,
        acciones: {
          eliminar: this.eliminar,
          editar: this.editar,
          ver_info: this.ver_info,
          bloquear: this.bloquear,
          ver_docs: this.ver_docs,
        },
      };

      await lastValueFrom(
        this._getbtbService.updateTable(this.idTable, obj_res)
      ).then(
        (data: any) => {
          if (!data.error) {
            /*           this.data_table = data.response;
             */ this._router.navigate(['sam/getbtb']);
            this._resourceService.openSnackBar('¡Modificación exitosa!');
          }
        },
        (error: HttpErrorResponse) => this._resourceService.checkErrors(error)
      );
    }
  }

  // Formulario de ubicación de la tabla
  private createFormUbication() {
    return new FormGroup({
      modulo_data: new FormControl(''),
      submodulo_data: new FormControl({ value: '', disabled: true }),
      menu_data: new FormControl({ value: '', disabled: true }),
      table_name: new FormControl(
        this.dataJSON.table_name,
        Validators.required
      ),
    });
  }

  // Formulario de tablas de la base de datos
  private createFormTableDB() {
    return new FormGroup({
      main_table: new FormControl('', Validators.required),
      relation_table: new FormControl({ value: [], disabled: true }),
    });
  }

  private createForm() {
    return new FormGroup({
      columns: new FormControl(
        { value: [], disabled: true },
        Validators.required
      ),
    });
  }

  public addCondition() {
    const dialogRef = this.dialog.open(GetbfoAddconditionComponent, {
      data: this.arr_columns,
      disableClose: true,
      width: '350px',
    });

    dialogRef.afterClosed().subscribe((result) => {
      if (result) this.arr_conditions.push(result);
    });
  }

  openRelationsInner() {
    let dataObj = {
      main_table: this.main_table?.value,
      arr_relationship: this.arr_relationship,
    };
    const dialogRef = this.dialog.open(TableDynManagementRelationsTable, {
      data: dataObj,
      disableClose: true,
      width: '850px',
    });

    dialogRef.afterClosed().subscribe((result) => {
      if (result) {
        this.columnsRelations.push(result.tables[0]);
        this.columnsRelations.push(result.tables[1]);
        this.columnsRelations = [...new Set(this.columnsRelations)];
        this.relation_table?.setValue(this.columnsRelations);

        this.arrayInners.push({
          nombre_tabla: result.dataForm.table_principal,
          columna: result.dataForm.column_relation,
          operador: result.dataForm.operator,
          innerType: result.dataForm.join_type,
          innerTable: result.dataForm.table_secondary,
          columnaInner: result.dataForm.column_compare,
        });
        this.dataColumns();
      } //this.arr_conditions.push(result);
    });
  }

  deleteItemJoin(index: any) {
    let postionObject = this.arrayInners[index];
    let contTable = 0;
    let contRelation = 0;

    for (let index = 0; index < this.arrayInners.length; index++) {
      if (
        postionObject.nombre_tabla == this.arrayInners[index].nombre_tabla ||
        postionObject.nombre_tabla == this.arrayInners[index].innerTable
      ) {
        contTable += 1;
      }

      if (
        postionObject.innerTable == this.arrayInners[index].innerTable ||
        postionObject.innerTable == this.arrayInners[index].nombre_tabla
      ) {
        contRelation += 1;
      }
    }

    if (contTable == 1) {
      let positon = this.arr_columns.findIndex((object: any) => {
        return object.table == postionObject.nombre_tabla;
      });

      if (positon > -1) {
        for (
          let index = 0;
          index < this.arr_columns[positon].columns.length;
          index++
        ) {
          for (
            let indexAux = 0;
            indexAux < this.columns?.value.length;
            indexAux++
          ) {
            if (
              this.arr_columns[positon].columns[index] ==
              this.columns?.value[indexAux]
            ) {
              this.columns?.value.splice(indexAux, 1);
            }
          }
        }

        for (let index = 0; index < this.model.length; index++) {
          if (this.model[index].db == postionObject.nombre_tabla) {
            this.model.splice(index, 1);
          }
        }
        this.arr_columns.splice(positon, 1);
      }
    }

    if (contRelation == 1) {
      let positionAux = this.arr_columns.findIndex((object: any) => {
        return object.table == postionObject.innerTable;
      });

      if (positionAux > -1) {
        for (
          let index = 0;
          index < this.arr_columns[positionAux].columns.length;
          index++
        ) {
          for (
            let indexAux = 0;
            indexAux < this.columns?.value.length;
            indexAux++
          ) {
            if (
              this.arr_columns[positionAux].columns[index] ==
              this.columns?.value[indexAux]
            ) {
              this.columns?.value.splice(indexAux, 1);
            }
          }
        }

        for (let index = 0; index < this.model.length; index++) {
          if (this.model[index].db == postionObject.innerTable) {
            this.model.splice(index, 1);
          }
        }
        this.arr_columns?.splice(positionAux, 1);
      }
    }

    this.arrayInners.splice(index, 1);
  }

  openQueryAdvance() {
    if (this.is_advance_search == true) {
      this.main_table?.reset();
      this.arrayInners = [];
      this.arr_conditions = [];
      this.menu_data?.reset();
      this.model = [];

      const dialogRef = this.dialog.open(TableDynManagementAdvanceQuery, {
        data: this.dataJSON.query,
        disableClose: true,
        width: '700px',
      });

      dialogRef.afterClosed().subscribe((result) => {
        this.query = result.query;
      });
    } else {
      this.query = '';
    }
  }

  deleteItemCondition(index: number) {
    this.arr_conditions.splice(index, 1);
  }

  get modulo_data() {
    return this.formGroupUbication.get('modulo_data');
  }

  get submodulo_data() {
    return this.formGroupUbication.get('submodulo_data');
  }

  get menu_data() {
    return this.formGroupUbication.get('menu_data');
  }

  get table_name() {
    return this.formGroupUbication.get('table_name');
  }

  get main_table() {
    return this.formGroupTableDB.get('main_table');
  }

  get relation_table() {
    return this.formGroupTableDB.get('relation_table');
  }
  get columns() {
    return this.formGroup.get('columns');
  }

  public setStep(index: number) {
    this.step = index;
  }
  public nextStep() {
    this.step++;
  }
  public prevStep() {
    this.step--;
  }
}

export interface TableData {
  CODIGO_TABLA: number;
  NOMBRE_TABLA: string;
}
