import { MatDialogRef } from '@angular/material/dialog';
import { EquipmentLruUploadComponent } from '../equipment-lru-upload/equipment-lru-upload.component';
import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatTableDataSource } from '@angular/material/table';
import { FunctionsService } from '../../../services/functions.service';
import { TempFileInfo } from '../../../interfaces/temp-file-info.interface';
import { ResourcesService } from '../../../services/resources.service';
import { lastValueFrom } from 'rxjs';
import { GdelService } from '../../../services/gdel.service';
import { PreviewExcelDocumentComponent } from '../preview-Equipmentexcel-document/preview-excel-document.component';
import * as XLSX from 'xlsx';
import { FormControl, Validators } from '@angular/forms';

const ID_MODULE = "S002V01M15IDUP";

export interface Document {
  nombre_del_archivo: string,
  tamano_del_archivo: string,
  archivo_id?: string,
  tipo_archivo?: string,
  fecha_carga?: string
}


interface SheetHeaderStructure {
  [column: string]: string;
}

interface TemplateStructure {
  [sheetName: string]: SheetHeaderStructure;
}

@Component({
  selector: 'app-individual-upload',
  standalone: false,
  templateUrl: './individual-upload.component.html',
  styleUrl: './individual-upload.component.css'
})

export class IndividualUploadComponent implements OnInit {

  public isLoading: boolean = false;
  public hasError: boolean = false;
  public errorMessage: string = '';
  public isUploading: boolean;

  uploadedFile: TempFileInfo | null;
  @ViewChild('file') private uploader?: ElementRef;

  moduleControl = new FormControl('', Validators.required);

  public dataSource: MatTableDataSource<Document>;
  public displayedColumns: string[] = ['nombre_del_archivo', 'tamano_del_archivo', 'acciones'];
  

  public excelFile: Document | null = null;
  public excelData: any = null;


  public isDragOver: boolean = false;


  private readonly EXCEL_EXTENSIONS = ['xlsx', 'xls'];
  private readonly MAX_FILE_SIZE_MB = 10;
  private readonly HEADER_ROW = 7; 


  private readonly TEMPLATE_STRUCTURE: TemplateStructure = {
    'CARGA DE EQUIPOS': {
      'B': 'TIPO / DESCRIPCIÓN',
      'C': 'ACRÓNIMO DEL EQUIPO',
      'D': 'MODELO COMPLETO',
      'E': 'ACRÓNIMO DEL MODELO',
      'F': 'ID',
      'G': 'NO.SERIE',
      'H': 'NO. CÓDIGO DE BARRAS',
      'I': 'CARÁCTER',
      'J': 'PROVEEDOR DEL EQUIPAMIENTO',
      'K': 'FECHA INICIO DE LA GARANTÍA',
      'L': 'FECHA FIN DE LA GARANTÍA',
      'M': 'FECHA DE ADQUSICIÓN DEL ARTÍCULO',
      'N': 'FECHA DE VENCIMIENTO DEL ARTÍCULO',
      'O': 'ETIQUETA FINAL DEL EQUIPO',
    },
    'LRU': {
      'B': 'TIPO / DESCRIPCIÓN',
      'C': 'ACRÓNIMO DEL EQUIPO',
      'D': 'MODELO COMPLETO',
      'E': 'ACRÓNIMO DEL MODELO',
      'F': 'ID',
      'G': 'NO.SERIE',
      'H': 'NO. CÓDIGO DE BARRAS',
      'I': 'CARÁCTER',
      'J': 'FECHA DE VENCIMIENTO DEL ARTÍCULO',
      'K': 'ETIQUETA FINAL DEL EQUIPO'
    },
    'CASO 1': {
      'B': 'LÍNEA',
      'D': 'UBICACIÓN',
      'F': 'NIVEL',
      'H': 'OCUPACIÓN',
      'J': 'ELEMENTO',
      'L': 'COORDENADAS PLANO GENERAL',
      'M': 'COORDENADAS DETALLE',
      'N': 'COORDENADAS DE POSICIÓN',
      'P': 'FAMILIA',
      'R': 'SUBFAMILIA',
      'T': 'ESTADO',
      'V': 'TIPO',
      'X': 'MODELO',
      'Z': 'ID',
      'AB': 'TIPO',
      'AD': 'MODELO',
      'AF': 'ID',
      'AH': 'CÓDIGO COMPLETO SAM',
      'AI': 'CÓDIGO EQUIVALENTE'
    },
    'CASO 2': {
      'B': 'LÍNEA',
      'D': 'UBICACIÓN',
      'F': 'NIVEL',
      'H': 'OCUPACIÓN',
      'J': 'ELEMENTO',
      'L': 'COORDENADAS PLANO GENERAL',
      'M': 'COORDENADAS DE POSICIÓN',
      'N': 'POSICIÓN EN RACK',
      'P': 'FAMILIA',
      'R': 'SUBFAMILIA',
      'T': 'ESTADO',
      'V': 'TIPO',
      'X': 'MODELO',
      'Z': 'ID',
      'AB': 'TIPO',
      'AD': 'MODELO',
      'AF': 'ID',
      'AH': 'CÓDIGO COMPLETO',
      'AI': 'CÓDIGO EQUIVALENTE' 
    },
    'CASO 3': {
      'B': 'LÍNEA',
      'D': 'UBICACIÓN ORIGEN',
      'F': 'NIVEL ORIGEN',
      'H': 'OCUPACIÓN ORIGEN',
      'J': 'ELEMENTO ORIGEN',
      'L': 'PK ORIGEN',
      'N': 'UBICACIÓN DESTINO',
      'P': 'NIVEL DESTINO',
      'R': 'OCUPACIÓN DESTINO',
      'T': 'ELEMENTO DESTINO',
      'V': 'PK DESTINO',
      'X': 'FAMILIA',
      'Z': 'SUBFAMILIA',
      'AB': 'ESTADO',
      'AD': 'TIPO',
      'AF': 'MODELO',
      'AH': 'ID',
      'AJ': 'TIPO',
      'AL': 'MODELO',
      'AN': 'ID',
      'AP': 'CÓDIGO COMPLETO',
      'AQ': 'CÓDIGO EQUIVALENTE'
    },
    'CASO 4': {
      'B': 'LÍNEA',
      'D': 'UBICACIÓN ORIGEN',
      'F': 'NIVEL ORIGEN',
      'H': 'OCUPACIÓN ORIGEN',
      'J': 'ELEMENTO ORIGEN',
      'L': 'SECUENCIAL ORIGEN',
      'N': 'COORDENADAS PLANO',
      'O': 'COORDENADAS DETALLE',
      'P': 'COORDENADAS DE POSICIÓN',
      'R': 'UBICACIÓN DESTINO',
      'T': 'NIVEL DESTINO',
      'V': 'OCUPACIÓN DESTINO',
      'X': 'ELEMENTO DESTINO',
      'Z': 'SECUENCIAL DESTINO',
      'AB': 'COORDENADAS PLANO',
      'AC': 'COORDENADAS DETALLE',
      'AD': 'COORDENADAS DE POSICIÓN',
      'AF': 'FAMILIA',
      'AH': 'SUBFAMILIA',
      'AJ': 'ESTADO',
      'AL': 'TIPO',
      'AN': 'MODELO',
      'AP': 'ID',
      'AR': 'TIPO',
      'AT': 'MODELO',
      'AV': 'ID',
      'AX': 'CÓDIGO COMPLETO',
      'AY': 'CÓDIGO EQUIVALENTE',
    },
    'CASO 5': {
      'B': 'LÍNEA',
      'D': 'UBICACIÓN',
      'F': 'NIVEL',
      'H': 'OCUPACIÓN',
      'J': 'ÁREA',
      'L': 'ELEMENTO',
      'N': 'FAMILIA',
      'P': 'SUBFAMILIA',
      'R': 'ESTADO',
      'T': 'TIPO',
      'V': 'MODELO',
      'X': 'ID',
      'Z': 'TIPO',
      'AB': 'MODELO',
      'AD': 'ID',
      'AF': 'CÓDIGO COMPLETO',
      'AG': 'CÓDIGO EQUIVALENTE', 
    },
    'CASO 6': {
      'B': 'LÍNEA',
      'D': 'UBICACIÓN',
      'F': 'NIVEL',
      'H': 'OCUPACIÓN',
      'J': 'ELEMENTO',
      'L': 'POSICIÓN',
      'N': 'FAMILIA',
      'P': 'SUBFAMILIA',
      'R': 'ESTADO',
      'T': 'TIPO',
      'V': 'MODELO',
      'X': 'ID',
      'Z': 'TIPO',
      'AB': 'MODELO',
      'AD': 'ID',
      'AF': 'CÓDIGO COMPLETO',
      'AG': 'CÓDIGO EQUIVALENTE',    
    }

  };

  private readonly CATÁLOGOS_STRUCTURE = {
    row5: {
      'B': 'FAMILIA',
      'C': 'ACRÓNIMO',
      'E': 'SUBFAMILIA',
      'F': 'ACRÓNIMO',
      'G': 'SUBFAMILY',
      'I': 'UBICACIONES (FRENTES)',
      'J': 'CÓDIGO',
      'L': 'RMS',
      'M': 'ELEMENTO',
      'N': 'CÓDIGO',
      'P': 'OCUPACIÓN',
      'Q': 'CÓDIGO',
      'S': 'ESTADO',
      'T': 'ACRÓNIMO'
    },

  };


  private readonly REQUIRED_SHEETS = ['CARGA DE EQUIPOS', 'LRU', 'CASO 1', 'CASO 2', 'CASO 3', 'CASO 4', 'CASO 5', 'CASO 6', 'CATÁLOGOS'];

  constructor (
    private dialogRef: MatDialogRef<EquipmentLruUploadComponent>,
    private _gdelService: GdelService,
    private _matDialog: MatDialog,
    private _functionService: FunctionsService,
    private _resourcesService: ResourcesService,
  ) {
    this.isLoading = false;
    this.isUploading = false;
    this.uploadedFile = null;
    this.dataSource = new MatTableDataSource();
  }

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

  cancelar(): void {
    this.dialogRef.close();
  }

  openFileUploader(): void {
    this.uploader?.nativeElement.click();
  }


  onDragOver(event: DragEvent): void {
    event.preventDefault();
    event.stopPropagation();
    this.isDragOver = true;
  }

  onDragLeave(event: DragEvent): void {
    event.preventDefault();
    event.stopPropagation();
    this.isDragOver = false;
  }

  onDrop(event: DragEvent): void {
    event.preventDefault();
    event.stopPropagation();
    this.isDragOver = false;

    const files = event.dataTransfer?.files;
    if (files && files.length > 0) {
      this.processFile(files[0]);
    }
  }

  checkFile(event: any): void {
    const file = event.target.files[0];
    if (!file) return;
    this.processFile(file);
  }

  private processFile(file: File): void {

    if (!this.isValidExcelFile(file)) {
      return;
    }

    if (!this.isValidFileSize(file)) {
      return;
    }

    this.isUploading = true;
    this.uploadExcelFile(file);
  }

  private isValidExcelFile(file: File): boolean {
    const fileName = file.name.toLowerCase();
    const fileExtension = fileName.split('.').pop();
    
    if (!fileExtension || !this.EXCEL_EXTENSIONS.includes(fileExtension)) {
      this._resourcesService.openSnackBar('Solo se permiten archivos Excel (.xlsx, .xls)');
      return false;
    }
    
    return true;
  }

  private isValidFileSize(file: File): boolean {
    const maxFileSize = this.MAX_FILE_SIZE_MB * 1024 * 1024;
    
    if (file.size > maxFileSize) {
      this._resourcesService.openSnackBar(`El tamaño del archivo supera el límite de ${this.MAX_FILE_SIZE_MB} MB`);
      return false;
    }
    
    return true;
  }


private validateExcelTemplate(workbook: XLSX.WorkBook): { isValid: boolean, errors: string[] } {
  const errors: string[] = [];
  

  const existingSheets = workbook.SheetNames;
  const missingSheets = this.REQUIRED_SHEETS.filter(sheet => !existingSheets.includes(sheet));
  
  if (missingSheets.length > 0) {
    errors.push(`Tu documento no cumple con las hojas requeridas de la plantilla`);
  }

  for (const sheetName of this.REQUIRED_SHEETS) {
    if (existingSheets.includes(sheetName)) {
      const sheetErrors = this.validateSheetHeaders(workbook.Sheets[sheetName], sheetName);
      errors.push(...sheetErrors);
      

      if (sheetName === 'CARGA DE EQUIPOS') {
        const dataErrors = this.validateSheetHasData(workbook.Sheets[sheetName], sheetName);
        errors.push(...dataErrors);
      }

    }
  }

  return {
    isValid: errors.length === 0,
    errors: errors
  };
}


private validateSheetHasData(worksheet: XLSX.WorkSheet, sheetName: string): string[] {
  const errors: string[] = [];
  
  try {

    const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1');
    
    
    const dataStartRow = this.HEADER_ROW + 2; 
    

    let hasData = false;
    

    if (range.e.r >= dataStartRow) {

      const mainColumns = ['B', 'D', 'F', 'H']; 
      
      for (let row = dataStartRow; row <= range.e.r; row++) {
        for (const col of mainColumns) {
          const cellAddress = `${col}${row}`;
          const cell = worksheet[cellAddress];
          
          
          if (cell && cell.v !== null && cell.v !== undefined && String(cell.v).trim() !== '') {
            hasData = true;
            break;
          }
        }
        if (hasData) break;
      }
    }
    
    if (!hasData) {
      errors.push(`La hoja "${sheetName}" no contiene datos. Se requiere al menos un registro con información.`);
    }
    
  } catch (error) {
    errors.push(`Error al validar datos en la hoja "${sheetName}": No se pudo verificar el contenido.`);
  }
  
  return errors;
}

  private validateSheetHeaders(worksheet: XLSX.WorkSheet, sheetName: string): string[] {
    const errors: string[] = [];
    

    if (sheetName === 'CATÁLOGOS') {
      return this.validateCatalogosSheet(worksheet);
    }
    
    const expectedHeaders = this.TEMPLATE_STRUCTURE[sheetName];
    
    if (!expectedHeaders) {
      errors.push(`No se encontró la estructura esperada para la hoja: ${sheetName}`);
      return errors;
    }


    const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1');
    
    for (const [column, expectedHeader] of Object.entries(expectedHeaders)) {
      const cellAddress = `${column}${this.HEADER_ROW}`;
      const cell = worksheet[cellAddress];
      const actualHeader = cell ? String(cell.v).trim() : '';
      
      if (actualHeader !== expectedHeader) {
        errors.push(`Tu documento tiene error en los Headers, revísalos e intentalo de nuevo`);
      }
    }

    return errors;
  }


  private validateCatalogosSheet(worksheet: XLSX.WorkSheet): string[] {
    const errors: string[] = [];

   
    for (const [column, expectedHeader] of Object.entries(this.CATÁLOGOS_STRUCTURE.row5)) {
      const cellAddress = `${column}5`;
      const cell = worksheet[cellAddress];
      const actualHeader = cell ? String(cell.v).trim() : '';
      
      if (actualHeader !== expectedHeader) {
        errors.push(`Hoja "CATÁLOGOS", Fila 5, Columna ${column}: Se esperaba "${expectedHeader}" pero se encontró "${actualHeader}"`);
      }
    }




    return errors;
  }

  async uploadExcelFile(fileData: File): Promise<void> {
    try {

      const validationResult = await this.validateFileStructure(fileData);
      
      if (!validationResult.isValid) {
        this._resourcesService.openSnackBar(`Plantilla inválida: ${validationResult.errors.join('. ')}`);
        this.isUploading = false;
        return;
      }

      const idUser = localStorage.getItem('idusuario');
      const formData = new FormData();

      formData.append('file', fileData);
      formData.append('id_user', idUser!);
      formData.append('linea', "1");
      formData.append('tipo_archivo', 'excel');

      const response = await lastValueFrom(this._gdelService.uploadTempFile(formData));

      if (response.error) {
        this._resourcesService.openSnackBar(response.msg);
      } else {

        this.uploadedFile = {
          id: response.response.idArchivo,
          name: fileData.name,
          size: this.formatBytes(fileData.size)
        };


        await this.readExcelFile(fileData, response.response.idArchivo);
        
        const newDocument: Document = {
          nombre_del_archivo: fileData.name,
          tamano_del_archivo: this.formatBytes(fileData.size),
          archivo_id: response.response.idArchivo,
          tipo_archivo: 'excel',
          fecha_carga: new Date().toLocaleString()
        };


        this.excelFile = newDocument;
        this.updateTableData();
        this._resourcesService.openSnackBar('Plantilla Excel válida y cargada exitosamente');
      }

      this.isUploading = false;
    } catch (error: any) {
      this.handleUploadError(error);
      this.isUploading = false;
    }
  }


  private async validateFileStructure(file: File): Promise<{ isValid: boolean, errors: string[] }> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (e: any) => {
        try {
          const data = new Uint8Array(e.target.result);
          const workbook = XLSX.read(data, { type: 'array' });
          
          const validation = this.validateExcelTemplate(workbook);
          resolve(validation);
        } catch (error) {
          reject(error);
        }
      };
      reader.onerror = reject;
      reader.readAsArrayBuffer(file);
    });
  }

  private async readExcelFile(file: File, fileId: any): Promise<void> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (e: any) => {
        try {
          const data = new Uint8Array(e.target.result);
          const workbook = XLSX.read(data, { type: 'array' });
          

          const sheetNames = workbook.SheetNames;
          const sheetsData: any = {};
          
          sheetNames.forEach(sheetName => {
            const worksheet = workbook.Sheets[sheetName];
            sheetsData[sheetName] = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
          });


          this.excelData = {
            fileName: file.name,
            sheets: sheetsData,
            sheetNames: sheetNames,
            fileId: fileId
          };

          resolve();
        } catch (error) {
          reject(error);
        }
      };
      reader.onerror = reject;
      reader.readAsArrayBuffer(file);
    });
  }

  async deleteTempFile(): Promise<void> {
    if (!this.uploadedFile) return;

    try {
      let idUser = localStorage.getItem('idusuario');
      let formData = new FormData();

      formData.append('id_user', idUser!);
      formData.append('id_file', this.uploadedFile.id);
      formData.append('linea', '1');

      await lastValueFrom(this._gdelService.deleteTempFile(formData));

      this.uploadedFile = null;
      this.excelFile = null;
      this.excelData = null;
      this.updateTableData();
      this._resourcesService.openSnackBar('Archivo eliminado exitosamente');
    } catch (error: any) {
      this.handleUploadError(error);
    }
  }

  formatBytes(bytes: number, decimals = 2): string {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
  }

  private updateTableData(): void {
    this.dataSource.data = this.excelFile ? [this.excelFile] : [];
  }

  private loadExcelFile(): void {

    this.excelFile = null;
    this.updateTableData();
  }

  private handleUploadError(error: any): void {
    if (error.error == undefined) {
      this._resourcesService.openSnackBar('Ocurrió un error inesperado.');
    } else if (error.error.msg == undefined) {
      this._resourcesService.openSnackBar('Ocurrió un error inesperado.');
    } else {
      this._resourcesService.openSnackBar(error.error.msg);
    }
  }

  previewExcelFile(): void {
    if (!this.excelData) {
      this._resourcesService.openSnackBar('No hay datos del archivo Excel para mostrar');
      return;
    }

    const dialogRef = this._matDialog.open(PreviewExcelDocumentComponent, {
      width: '1800px',
      height: '900px',
      maxWidth: '1800px',
      data: this.excelData,
      disableClose: true
    });

    dialogRef.afterClosed().subscribe(result => {

      if (result) {
        console.log('Preview cerrado:', result);
      }
    });
  }

  removeExcelFile(): void {
    this.deleteTempFile();
  }


  get hasExcelFile(): boolean {
    return this.excelFile !== null;
  }

  get excelFiles(): Document[] {
    return this.excelFile ? [this.excelFile] : [];
  }


  async saveFinalFile(): Promise<void> {
    if (!this.uploadedFile) {
      this._resourcesService.openSnackBar('No hay archivo cargado para guardar');
      return;
    }

    try {
      this.isLoading = true;
      let idUser = localStorage.getItem('idusuario');
      let formData = new FormData();


      formData.append('id_user', idUser!);
      formData.append('id_file', this.uploadedFile.id);
      formData.append('linea', '1');
      

      formData.append('module', 'ADSI'); 
      formData.append('clasification', 'LA'); 
      formData.append('has_order', 'N'); 

      console.log('Datos enviados al servidor:', {
        id_user: idUser,
        id_file: this.uploadedFile.id,
        module: 'ADSI',
        clasification: 'LA'
      });

      const response = await lastValueFrom(this._gdelService.saveFinalFile(formData));
      
      console.log('Respuesta del servidor:', response);

      if (response.error) {
        throw new Error(response.msg || 'Error al guardar el archivo');
      }

      this._resourcesService.openSnackBar('Archivo guardado correctamente');
      this.dialogRef.close(true); 
    } catch (error: any) {
      console.error('Error al guardar archivo:', error);
      this._resourcesService.openSnackBar(error.message || 'Error al guardar el archivo');
    } finally {
      this.isLoading = false;
    }
  }
}