package main import ( "encoding/csv" "fmt" "log" "os" "strings" "time" "heating-monitor/internal/bot" "heating-monitor/internal/config" "github.com/spf13/cobra" "gorm.io/gorm" ) func main() { var filePath string var dryRun bool // Define el comando principal var cmd = &cobra.Command{ Use: "import", Short: "Importa datos desde un CSV a la base de datos", Run: func(cmd *cobra.Command, args []string) { if filePath == "" { log.Fatal("Debe especificar un archivo CSV con el flag -f o --file") } // Abre el archivo CSV file, err := os.Open(filePath) if err != nil { log.Fatalf("No se pudo abrir el archivo: %v", err) } defer file.Close() reader := csv.NewReader(file) reader.Comma = ';' // Usamos punto y coma como separador // Lee el archivo CSV records, err := reader.ReadAll() if err != nil { log.Fatalf("Error al leer el archivo CSV: %v", err) } // Ignorar la primera línea de encabezado records = records[1:] insertedCount := 0 // Procesa cada línea del CSV for _, record := range records { // Ignorar encabezado if strings.HasPrefix(record[0], ";") { continue } // Parsear la fecha fecha, err := time.Parse("2006-01-02", record[1]) if err != nil { log.Printf("Error al parsear la fecha: %v", err) continue } // Procesar las columnas ON/OFF for i := 2; i <= 6; i += 3 { if record[i] != "" && record[i+1] != "" { // Parsear las horas ON/OFF onTime, err := time.Parse("15:04", record[i]) if err != nil { log.Printf("Error al parsear hora ON: %v", err) continue } offTime, err := time.Parse("15:04", record[i+1]) if err != nil { log.Printf("Error al parsear hora OFF: %v", err) continue } // Ajustar los tiempos a la fecha correcta onTimestamp := time.Date(fecha.Year(), fecha.Month(), fecha.Day(), onTime.Hour(), onTime.Minute(), 0, 0, time.UTC) offTimestamp := time.Date(fecha.Year(), fecha.Month(), fecha.Day(), offTime.Hour(), offTime.Minute(), 0, 0, time.UTC) // Mostrar en dry-run if dryRun { fmt.Printf("ON: %v, OFF: %v\n", onTimestamp, offTimestamp) } else { // Inicializar la base de datos config.InitDB() // Insertar en la base de datos existsOn, err := eventExists(config.DB, "ON", onTimestamp) if err != nil { log.Printf("Error al verificar existencia de evento ON: %v", err) continue } if !existsOn { err := insertHeatingEvent(config.DB, "ON", onTimestamp) if err != nil { log.Printf("Error al insertar evento ON: %v", err) continue } insertedCount++ } else { log.Printf("Evento ON ya existe: %v", onTimestamp) } existsOff, err := eventExists(config.DB, "OFF", offTimestamp) if err != nil { log.Printf("Error al verificar existencia de evento OFF: %v", err) continue } if !existsOff { err := insertHeatingEvent(config.DB, "OFF", offTimestamp) if err != nil { log.Printf("Error al insertar evento OFF: %v", err) continue } insertedCount++ } else { log.Printf("Evento OFF ya existe: %v", offTimestamp) } } } } } log.Printf("Se insertaron %d registros en la base de datos", insertedCount) }, } // Añadir flags al comando cmd.Flags().StringVarP(&filePath, "file", "f", "", "Ruta del archivo CSV") cmd.Flags().BoolVarP(&dryRun, "dry-run", "", false, "Simula la importación y muestra los datos") // Ejecutar el comando if err := cmd.Execute(); err != nil { log.Fatal(err) } } // insertHeatingEvent inserta un evento de calefacción en la base de datos func insertHeatingEvent(db *gorm.DB, eventType string, timestamp time.Time) error { event := bot.HeatingEvent{ EventType: eventType, Timestamp: timestamp, } // Insertar el evento en la base de datos if err := db.Create(&event).Error; err != nil { return fmt.Errorf("no se pudo insertar el evento: %v", err) } return nil } // eventExists verifica si un evento con el mismo tipo y timestamp ya existe func eventExists(db *gorm.DB, eventType string, timestamp time.Time) (bool, error) { var existingEvent bot.HeatingEvent err := db.Where("event_type = ? AND timestamp = ?", eventType, timestamp).First(&existingEvent).Error if err == nil { // Si err es nil, significa que se encontró un evento existente return true, nil } else if err == gorm.ErrRecordNotFound { // Si el error es ErrRecordNotFound, no existe el evento return false, nil } // Si hay otro tipo de error return false, err }