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';
import { PreviewDocumentsComponent } from '../preview-documents/preview-documents.component';

const ID_MODULE = "S002V01M15IDUP";

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

// Interfaz para la estructura de headers esperados
interface SheetHeaderStructure {
  [column: string]: string;
}

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

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

export class IndividualPreventiveUploadComponent 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'];
  
  // Variables para manejar archivos Excel (solo uno permitido)
  public excelFile: Document | null = null;
  public excelData: any = null;

  // Variables para drag and drop
  public isDragOver: boolean = false;

  // Configuración específica para archivos Excel
  private readonly EXCEL_EXTENSIONS = ['xlsx', 'xls'];
  private readonly MAX_FILE_SIZE_MB = 10;
  private readonly HEADER_ROW = 6; // Los headers están en la fila 6

  // Estructura de la plantilla esperada
  private readonly TEMPLATE_STRUCTURE: TemplateStructure = {
    'CALENDARIO': {
      'B': 'CÓDIGO EQUIVALENTE',
      'D': 'CÓDIGO DEL EQUIPO',
      'F': 'CÓDIGO DEL LRU',
      'H': 'FECHA Y HORA DE INTERVENCIÓN',
      'J': 'TIEMPO DE INMOVILIZACIÓN ESTIMADO',
      'L': 'DESCRIPCIÓN DE LA INTERVENCIÓN',
      'N': 'TIPO DE ACTIVACIÓN',
      'P': 'REPETICIÓN',
      'R': 'DÍA',
      'T': 'DÍA SEMANA',
      'V': 'MES',
      'X': 'CANTIDAD DE INTERVENCIONES',
      'AA': 'CLASIFICACIÓN',
      'AC': 'PRIORIDAD',
      'AE': 'ESPECIALIDADES DEL OPERARIO',
      'AG': 'CANTIDAD DE OPERARIOS PREVISTOS',
      'AI': 'ARTÍCULOS A UTILIZAR',
      'AK': 'INSTRUCCIONES',
      'AM': 'OBSERVACIONES',
      'AO': 'DETALLES ADICIONALES'
    },
    'SÍNTOMA': {
      'B': 'CÓDIGO EQUIVALENTE',
      'D': 'CÓDIGO DEL EQUIPO',
      'F': 'CÓDIGO DEL LRU',
      'H': 'FECHA Y HORA DE INTERVENCIÓN',
      'J': 'TIEMPO DE INMOVILIZACIÓN ESTIMADO',
      'L': 'DESCRIPCIÓN DE LA INTERVENCIÓN',
      'N': 'TIPO DE ACTIVACIÓN',
      'P': 'REPETICIÓN',
      'R': 'DÍA SEMANA',
      'T': 'DÍA',
      'V': 'MES',
      'X': 'CANTIDAD DE INTERVENCIONES',
      'Z': 'SÍNTOMAS DEL EQUIPAMIENTO',
      'AB': 'CLASIFICACIÓN',
      'AD': 'PRIORIDAD',
      'AF': 'ESPECIALIDADES DEL OPERARIO',
      'AH': 'CANTIDAD DE OPERARIOS PREVISTOS',
      'AJ': 'ARTÍCULOS A UTILIZAR',
      'AL': 'OBSERVACIONES',
      'AN': 'DETALLES ADICIONALES'
    },
    'MEDIDA': {
      'B': 'CÓDIGO EQUIVALENTE',
      'D': 'CÓDIGO DEL EQUIPO',
      'F': 'CÓDIGO DEL LRU',
      'H': 'FECHA Y HORA DE INTERVENCIÓN',
      'J': 'TIEMPO DE INMOVILIZACIÓN ESTIMADO',
      'L': 'DESCRIPCIÓN DE LA INTERVENCIÓN',
      'N': 'TIPO DE ACTIVACIÓN',
      'P': 'VALOR',
      'R': 'MAGNITUD',
      'T': 'UNIDAD',
      'V': 'SÍMBOLO',
      'X': 'CANTIDAD',
      'Z': 'MAGNITUD',
      'AB': 'UNIDAD',
      'AD': 'SÍMBOLO',
      'AF': 'CLASIFICACIÓN',
      'AH': 'PRIORIDAD',
      'AJ': 'ESPECIALIDADES DEL OPERARIO',
      'AL': 'CANTIDAD DE OPERARIOS PREVISTOS',
      'AN': 'ARTÍCULOS A UTILIZAR',
      'AP': 'OBSERVACIONES',
      'AR': 'DETALLES ADICIONALES'
    },
    'VALOR': {
      'B': 'CÓDIGO EQUIVALENTE',
      'C': 'CÓDIGO DEL EQUIPO',
      'E': 'CÓDIGO DEL LRU',
      'G': 'FECHA Y HORA DE INTERVENCIÓN',
      'I': 'TIEMPO DE INMOVILIZACIÓN ESTIMADO',
      'K': 'DESCRIPCIÓN DE LA INTERVENCIÓN',
      'M': 'TIPO DE ACTIVACIÓN',
      'O': 'CANTIDAD',
      'Q': 'MAGNITUD',
      'S': 'UNIDAD',
      'U': 'SÍMBOLO',
      'W': 'CLASIFICACIÓN',
      'Y': 'PRIORIDAD',
      'AA': 'ESPECIALIDADES DEL OPERARIO',
      'AC': 'CANTIDAD DE OPERARIOS PREVISTOS',
      'AE': 'ARTÍCULOS A UTILIZAR',
      'AG': 'OBSERVACIONES',
      'AI': 'DETALLES ADICIONALES'
    }
  };

  // Estructura especial para la hoja CATÁLOGOS que tiene headers en filas 3 y 4
  private readonly CATALOGOS_STRUCTURE = {
    row3: {
      'F': 'CLASIFICACIONES',
      'H': 'ESPECIALIDADES',
      'J': 'FRECUENCIAS DE MANTENIMIENTO',
      'L': 'MESES',
      'N': 'PRIORIDADES'
    },
    row4: {
      'B': 'MAGNITUD',
      'C': 'UNIDAD',
      'D': 'SÍMBOLO'
    }
  };

  // Hojas requeridas en la plantilla
  private readonly REQUIRED_SHEETS = ['CALENDARIO', 'SÍNTOMA', 'MEDIDA', 'VALOR', '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();
  }

  // Métodos para drag and drop
  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 {
    // Validación específica para archivos Excel
    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; // Convertir MB a bytes
    
    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;
  }

// Método para validar la estructura de la plantilla Y que tenga datos
private validateExcelTemplate(workbook: XLSX.WorkBook): { isValid: boolean, errors: string[] } {
  const errors: string[] = [];
  
  // Verificar que existan todas las hojas requeridas
  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`);
  }

  // Validar headers de cada hoja Y verificar que tengan datos
  for (const sheetName of this.REQUIRED_SHEETS) {
    if (existingSheets.includes(sheetName)) {
      const sheetErrors = this.validateSheetHeaders(workbook.Sheets[sheetName], sheetName);
      errors.push(...sheetErrors);
      
      if (sheetName === 'CALENDARIO') {
        const dataErrors = this.validateSheetHasData(workbook.Sheets[sheetName], sheetName);
        errors.push(...dataErrors);
      }

      if (sheetName === 'SÍNTOMA') {
        const dataErrors = this.validateSheetHasData(workbook.Sheets[sheetName], sheetName);
        errors.push(...dataErrors);
      }

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

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

      if (sheetName === 'CATÁLOGOS') {
        const dataErrors = this.validateSheetHasData(workbook.Sheets[sheetName], sheetName);
        errors.push(...dataErrors);
      }
    }
  }

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

// Nuevo método para validar que una hoja tenga datos
private validateSheetHasData(worksheet: XLSX.WorkSheet, sheetName: string): string[] {
  const errors: string[] = [];
  
  try {
    // Obtener el rango de la hoja
    const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1');
    
    // Para MANTENIMIENTO CORRECTIVO, los datos empiezan después de la fila de headers (fila 7 en adelante)
    const dataStartRow = this.HEADER_ROW + 2; // Fila 7
    
    // Verificar si hay al menos una fila con datos después de los headers
    let hasData = false;
    
    // Revisar desde la fila de datos hasta el final del rango
    if (range.e.r >= dataStartRow) {
      // Revisar las columnas principales para ver si hay datos
      const mainColumns = ['B', 'D', 'F', 'H']; // Las primeras columnas importantes
      
      for (let row = dataStartRow; row <= range.e.r; row++) {
        for (const col of mainColumns) {
          const cellAddress = `${col}${row}`;
          const cell = worksheet[cellAddress];
          
          // Si encontramos una celda con contenido (no vacía, no null, no undefined)
          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;
}


  // Método para validar los headers de una hoja específica
  private validateSheetHeaders(worksheet: XLSX.WorkSheet, sheetName: string): string[] {
    const errors: string[] = [];
    
    // Validación especial para la hoja CATÁLOGOS
    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;
    }

    // Obtener los headers de la fila especificada (fila 6)
    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(`Hoja "${sheetName}", Columna ${column}: Se esperaba "${expectedHeader}" pero se encontró "${actualHeader}"`);
      }
    }

    return errors;
  }

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


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

    // Validar headers de la fila 4
    for (const [column, expectedHeader] of Object.entries(this.CATALOGOS_STRUCTURE.row4)) {
      const cellAddress = `${column}4`;
      const cell = worksheet[cellAddress];
      const actualHeader = cell ? String(cell.v).trim() : '';
      
      if (actualHeader !== expectedHeader) {
        errors.push(`Hoja "CATÁLOGOS", Fila 4, Columna ${column}: Se esperaba "${expectedHeader}" pero se encontró "${actualHeader}"`);
      }
    }

    return errors;
  }

  async uploadExcelFile(fileData: File): Promise<void> {
    try {
      // Primero validar la estructura antes de subir
      const validationResult = await this.validateFileStructure(fileData);
      
      if (!validationResult.isValid) {
        this._resourcesService.openSnackBar(`Debe contener al menos un registro y cumplir con la estructura requerida`);
        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 {
        // Actualizar uploadedFile para compatibilidad
        this.uploadedFile = {
          id: response.response.idArchivo,
          name: fileData.name,
          size: this.formatBytes(fileData.size)
        };

        // Leer el archivo Excel para obtener información adicional
        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()
        };

        // Solo mantener un archivo
        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;
    }
  }

  // Método para validar la estructura del archivo antes de subirlo
  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' });
          
          // Obtener información de las hojas
          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 });
          });

          // Guardar datos del archivo para previsualización
          this.excelData = {
            fileName: file.name,
            sheets: sheetsData,
            sheetNames: sheetNames,
            fileId: fileId
          };

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

  // Método para eliminar archivo temporal
  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 {
    // Inicializar con archivo vacío
    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);
    }
  }

  // Método para abrir previsualización del Excel
  previewExcelFile(): void {
    if (!this.excelData) {
      this._resourcesService.openSnackBar('No hay datos del archivo Excel para mostrar');
      return;
    }

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

    dialogRef.afterClosed().subscribe(result => {
      // Manejar el resultado si es necesario
      if (result) {
        console.log('Preview cerrado:', result);
      }
    });
  }

  // Método para eliminar archivo
  removeExcelFile(): void {
    this.deleteTempFile();
  }

  // Getter para verificar si ya hay un archivo cargado
  get hasExcelFile(): boolean {
    return this.excelFile !== null;
  }

  // Getter para obtener el array de archivos para la tabla
  get excelFiles(): Document[] {
    return this.excelFile ? [this.excelFile] : [];
  }

  // Método para guardar archivo final
  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();

      // Parámetros obligatorios
      formData.append('id_user', idUser!);
      formData.append('id_file', this.uploadedFile.id);
      formData.append('linea', '1');
      
      // Parámetros específicos para equipamiento
      formData.append('module', 'ADSI'); // Módulo fijo para equipamiento
      formData.append('clasification', 'LA'); // Clasificación fija para LRU/Equipamiento
      formData.append('has_order', 'N'); // Sin orden asociada

      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); // Cierra el diálogo y notifica al padre
    } catch (error: any) {
      console.error('Error al guardar archivo:', error);
      this._resourcesService.openSnackBar(error.message || 'Error al guardar el archivo');
    } finally {
      this.isLoading = false;
    }
  }
}