package repository import ( "fmt" "time" "users_management/m/model/entity" "github.com/google/uuid" "gorm.io/gorm" ) type DevicesRepo interface { Post(device entity.Device) error GetAll() ([]entity.Device, error) Update(id uuid.UUID, updates map[string]interface{}) error GetByID(id uuid.UUID) (entity.Device, error) GetByType(deviceType string) ([]entity.Device, error) BulkUpdateImages(updates map[uuid.UUID]string) error BulkUpdateImagesMultiple(updates map[uuid.UUID][]string) error SyncTowerLocationWithDevice(deviceID uuid.UUID) error ValidateTowerExists(towerID uuid.UUID) (bool, error) // Bulk operations BulkCreate(devices []entity.Device) ([]entity.Device, []error) BulkUpdate(ids []uuid.UUID, updates map[string]interface{}) (int64, error) BulkDelete(ids []uuid.UUID) (int64, error) } type devicesRepo struct { db *gorm.DB } func NewDevicesRepo(db *gorm.DB) DevicesRepo { return &devicesRepo{ db: db, } } func (r *devicesRepo) SyncTowerLocationWithDevice(deviceID uuid.UUID) error { return r.db.Transaction(func(tx *gorm.DB) error { // Get device details var device entity.Device if err := tx.Where("id = ?", deviceID).First(&device).Error; err != nil { return fmt.Errorf("device not found: %w", err) } // Update tower location if device has a tower assigned if device.TowerID != nil { if err := tx.Model(&entity.Tower{}). Where("id = ?", *device.TowerID). Updates(map[string]interface{}{ "longitude": device.Longitude, "latitude": device.Latitude, "updated_at": time.Now(), }).Error; err != nil { return fmt.Errorf("failed to sync tower location: %w", err) } } // Also update any towers that reference this device via dev_id if err := tx.Model(&entity.Tower{}). Where("dev_id = ?", deviceID). Updates(map[string]interface{}{ "longitude": device.Longitude, "latitude": device.Latitude, "updated_at": time.Now(), }).Error; err != nil { return fmt.Errorf("failed to sync related towers location: %w", err) } return nil }) } func (r *devicesRepo) ValidateTowerExists(towerID uuid.UUID) (bool, error) { var count int64 err := r.db.Model(&entity.Tower{}).Where("id = ?", towerID).Count(&count).Error return count > 0, err } func (r *devicesRepo) BulkUpdateImages(updates map[uuid.UUID]string) error { multipleUpdates := make(map[uuid.UUID][]string) for deviceID, imageURL := range updates { multipleUpdates[deviceID] = []string{imageURL} } return r.BulkUpdateImagesMultiple(multipleUpdates) } func (r *devicesRepo) BulkUpdateImagesMultiple(updates map[uuid.UUID][]string) error { return r.db.Transaction(func(tx *gorm.DB) error { for deviceID, imageURLs := range updates { updateFields := map[string]interface{}{ "updated_at": time.Now(), } if len(imageURLs) > 0 { // Set primary image (first one) updateFields["image_url"] = imageURLs[0] // Set all images using StringSlice updateFields["image_urls"] = entity.StringSlice(imageURLs) } if err := tx.Model(&entity.Device{}). Where("id = ?", deviceID). Updates(updateFields).Error; err != nil { return fmt.Errorf("failed to update device %s: %w", deviceID, err) } } return nil }) } func (r *devicesRepo) Post(device entity.Device) error { return r.db.Transaction(func(tx *gorm.DB) error { // Create the device first if err := tx.Create(&device).Error; err != nil { return err } // Create the corresponding DevicePort record customerCount := 0 customerNames := make([]string, 0) // For ODP devices, initialize customer tracking if device.DeviceType == "ODP" { // Customer count starts at 0, will be updated when fishbones are connected customerCount = 0 } devicePort := entity.DevicePort{ ID: uuid.New(), DeviceID: device.ID, PortUsed: 0, PortAvailable: device.PortAmount, CustomerCount: customerCount, CustomerNames: customerNames, CreatedAt: time.Now(), UpdatedAt: time.Now(), } if err := tx.Create(&devicePort).Error; err != nil { return err } // Sync tower location with device location if device.TowerID != nil { if err := tx.Model(&entity.Tower{}). Where("id = ?", *device.TowerID). Updates(map[string]interface{}{ "longitude": device.Longitude, "latitude": device.Latitude, "updated_at": time.Now(), }).Error; err != nil { return fmt.Errorf("failed to sync tower location: %w", err) } } return nil }) } func (r *devicesRepo) GetAll() ([]entity.Device, error) { var devices []entity.Device err := r.db.Find(&devices).Error if err != nil { return devices, err } return devices, nil } func (r *devicesRepo) Update(id uuid.UUID, updates map[string]interface{}) error { return r.db.Transaction(func(tx *gorm.DB) error { // Validate tower exists if TowerID is being updated if towerID, exists := updates["TowerID"]; exists && towerID != nil { towerUUID := towerID.(uuid.UUID) var towerExists bool var err error if towerExists, err = r.ValidateTowerExists(towerUUID); err != nil { return fmt.Errorf("failed to validate tower: %w", err) } if !towerExists { return fmt.Errorf("tower with ID %s not found", towerUUID.String()) } } // Update device if err := tx.Model(&entity.Device{}).Where("id = ?", id).Updates(updates).Error; err != nil { return err } // If location is updated, sync with tower if _, hasLng := updates["Longitude"]; hasLng { if _, hasLat := updates["Latitude"]; hasLat { if err := r.SyncTowerLocationWithDevice(id); err != nil { return err } } } // If TowerID is updated, sync location if _, exists := updates["TowerID"]; exists { if err := r.SyncTowerLocationWithDevice(id); err != nil { return err } } return nil }) } func (r *devicesRepo) GetByID(id uuid.UUID) (entity.Device, error) { var device entity.Device err := r.db.Where("id = ?", id).First(&device).Error if err != nil { return device, err } return device, nil } func (r *devicesRepo) GetByType(deviceType string) ([]entity.Device, error) { var devices []entity.Device err := r.db.Where("device_type = ?", deviceType).Find(&devices).Error if err != nil { return devices, err } return devices, nil } // BulkCreate creates multiple devices in a single transaction func (r *devicesRepo) BulkCreate(devices []entity.Device) ([]entity.Device, []error) { var errors []error // Use transaction for bulk insert err := r.db.Transaction(func(tx *gorm.DB) error { if err := tx.CreateInBatches(devices, 50).Error; err != nil { return err } return nil }) if err != nil { errors = append(errors, err) return nil, errors } return devices, nil } // BulkUpdate updates multiple devices with the same values func (r *devicesRepo) BulkUpdate(ids []uuid.UUID, updates map[string]interface{}) (int64, error) { if len(updates) == 0 { return 0, nil } result := r.db.Model(&entity.Device{}).Where("id IN ?", ids).Updates(updates) return result.RowsAffected, result.Error } // BulkDelete deletes multiple devices func (r *devicesRepo) BulkDelete(ids []uuid.UUID) (int64, error) { result := r.db.Delete(&entity.Device{}, "id IN ?", ids) return result.RowsAffected, result.Error }