package usecase import ( "errors" "fmt" "time" "users_management/m/model/dto/req" "users_management/m/model/dto/res" "users_management/m/model/entity" "users_management/m/repository" "users_management/m/utils/helper" "users_management/m/utils/service" "github.com/go-playground/validator/v10" "github.com/google/uuid" ) type DeviceDetailsUseCase interface { CreateDeviceDetails(device req.DeviceDetailsDTO) error GetAllDeviceDetails() ([]res.DeviceDetailsResponse, error) GetDeviceDetailsByID(id uuid.UUID) (res.DeviceDetailsResponse, error) UpdateDeviceDetails(id uuid.UUID, device req.UpdateDeviceDetailsDTO) error DeleteDeviceDetails(id uuid.UUID) error // Port management // ValidatePortUsage(deviceID uuid.UUID, requiredPorts int) error RecalculatePortUsage(deviceID uuid.UUID) error } type deviceDetailsUseCase struct { deviceDetailsRepo repository.DeviceDetailsRepo geocoder service.GeocodingService validate *validator.Validate } func NewDeviceDetailsUseCase(deviceDetailsRepo repository.DeviceDetailsRepo, geocoder service.GeocodingService) DeviceDetailsUseCase { return &deviceDetailsUseCase{ deviceDetailsRepo: deviceDetailsRepo, geocoder: geocoder, validate: validator.New(), } } func (u *deviceDetailsUseCase) CreateDeviceDetails(deviceDTO req.DeviceDetailsDTO) error { err := u.validate.Struct(deviceDTO) if err != nil { return fmt.Errorf("validation error: %w", err) } newDevice := entity.Device{ ID: uuid.New(), DeviceCode: deviceDTO.DeviceCode, DeviceType: entity.DeviceType(deviceDTO.DeviceType), Longitude: deviceDTO.Longitude, Latitude: deviceDTO.Latitude, PortAmount: deviceDTO.PortAmount, Status: entity.DeviceStatus(deviceDTO.Status), Province: deviceDTO.Province, City: deviceDTO.City, District: deviceDTO.District, CreatedAt: time.Now(), UpdatedAt: time.Now(), } return u.deviceDetailsRepo.Create(newDevice) } func (u *deviceDetailsUseCase) GetAllDeviceDetails() ([]res.DeviceDetailsResponse, error) { devices, err := u.deviceDetailsRepo.GetAll() if err != nil { return nil, err } return helper.ConvertToDeviceDetailsResponses(devices, u.geocoder) } func (u *deviceDetailsUseCase) GetDeviceDetailsByID(id uuid.UUID) (res.DeviceDetailsResponse, error) { device, err := u.deviceDetailsRepo.GetByID(id) if err != nil { return res.DeviceDetailsResponse{}, err } return helper.ConvertToDeviceDetailsResponse(device, u.geocoder) } func (u *deviceDetailsUseCase) UpdateDeviceDetails(id uuid.UUID, deviceDTO req.UpdateDeviceDetailsDTO) error { err := u.validate.Struct(deviceDTO) if err != nil { return fmt.Errorf("validation error: %w", err) } // Check if device exists updates := map[string]interface{}{} if deviceDTO.DeviceCode != nil { updates["device_code"] = *deviceDTO.DeviceCode } if deviceDTO.DeviceType != nil { updates["device_type"] = *deviceDTO.DeviceType } if deviceDTO.Longitude != nil { updates["longitude"] = *deviceDTO.Longitude } if deviceDTO.Latitude != nil { updates["latitude"] = *deviceDTO.Latitude } if deviceDTO.PortAmount != nil { // Validate port amount change currentUsed, _, err := u.deviceDetailsRepo.GetPortUsageByDevice(id) if err != nil { return err } if *deviceDTO.PortAmount < currentUsed { return fmt.Errorf("cannot reduce port amount to %d, currently using %d ports", *deviceDTO.PortAmount, currentUsed) } updates["port_amount"] = *deviceDTO.PortAmount } if deviceDTO.Status != nil { updates["status"] = *deviceDTO.Status } if deviceDTO.Region != nil { updates["region"] = *deviceDTO.Region } if deviceDTO.Province != nil { updates["province"] = *deviceDTO.Province } if deviceDTO.City != nil { updates["city"] = *deviceDTO.City } if deviceDTO.District != nil { updates["district"] = *deviceDTO.District } if len(updates) == 0 { return errors.New("no fields to update") } updates["updated_at"] = time.Now() return u.deviceDetailsRepo.Update(id, updates) } func (u *deviceDetailsUseCase) DeleteDeviceDetails(id uuid.UUID) error { // Check if device has connections backbones, err := u.deviceDetailsRepo.GetBackbonesByDeviceID(id) if err != nil { return err } if len(backbones) > 0 { return errors.New("cannot delete device with active backbone connections") } fishbones, err := u.deviceDetailsRepo.GetFishbonesByDeviceID(id) if err != nil { return err } if len(fishbones) > 0 { return errors.New("cannot delete device with active fishbone connections") } towers, err := u.deviceDetailsRepo.GetTowersByDeviceID(id) if err != nil { return err } if len(towers) > 0 { return errors.New("cannot delete device with active tower connections") } return u.deviceDetailsRepo.Delete(id) } func (u *deviceDetailsUseCase) RecalculatePortUsage(deviceID uuid.UUID) error { return u.deviceDetailsRepo.UpdateDevicePortUsage(deviceID) }