package repository import ( "context" "bugulma/backend/internal/domain" "gorm.io/gorm" ) // ResourceFlowRepository implements domain.ResourceFlowRepository with GORM type ResourceFlowRepository struct { *BaseRepository[domain.ResourceFlow] } // NewResourceFlowRepository creates a new GORM-based resource flow repository func NewResourceFlowRepository(db *gorm.DB) domain.ResourceFlowRepository { return &ResourceFlowRepository{ BaseRepository: NewBaseRepository[domain.ResourceFlow](db), } } // GetBySiteID retrieves resource flows at a specific site func (r *ResourceFlowRepository) GetBySiteID(ctx context.Context, siteID string) ([]*domain.ResourceFlow, error) { return r.FindWhereWithContext(ctx, "site_id = ?", siteID) } // GetByOrganizationID retrieves resource flows owned by a specific organization func (r *ResourceFlowRepository) GetByOrganizationID(ctx context.Context, organizationID string) ([]*domain.ResourceFlow, error) { return r.FindWhereWithContext(ctx, "organization_id = ?", organizationID) } // GetByTypeAndDirection retrieves resource flows by type and direction func (r *ResourceFlowRepository) GetByTypeAndDirection(ctx context.Context, resType domain.ResourceType, direction domain.ResourceDirection) ([]*domain.ResourceFlow, error) { return r.FindWhereWithContext(ctx, "type = ? AND direction = ?", resType, direction) } // GetOutputsInRadius retrieves output resource flows within a geographic radius func (r *ResourceFlowRepository) GetOutputsInRadius(ctx context.Context, lat, lng, radiusKm float64, resType domain.ResourceType) ([]*domain.ResourceFlow, error) { var flows []*domain.ResourceFlow dialector := r.DB().Dialector.Name() if dialector == "postgres" { query := ` SELECT rf.* FROM resource_flows rf JOIN sites s ON rf.site_id = s.id WHERE rf.direction = 'output' AND rf.type = ? AND s.latitude IS NOT NULL AND s.longitude IS NOT NULL AND ( 6371 * acos( cos(radians(?)) * cos(radians(s.latitude)) * cos(radians(s.longitude) - radians(?)) + sin(radians(?)) * sin(radians(s.latitude)) ) ) <= ? ` result := r.DB().WithContext(ctx).Raw(query, resType, lat, lng, lat, radiusKm).Scan(&flows) if result.Error != nil { return nil, result.Error } } else { // Fallback to simple bounding box for SQLite query := ` SELECT rf.* FROM resource_flows rf JOIN sites s ON rf.site_id = s.id WHERE rf.direction = 'output' AND rf.type = ? AND s.latitude IS NOT NULL AND s.longitude IS NOT NULL AND abs(s.latitude - ?) <= 0.09 AND abs(s.longitude - ?) <= 0.15 ` result := r.DB().WithContext(ctx).Raw(query, resType, lat, lng).Scan(&flows) if result.Error != nil { return nil, result.Error } } return flows, nil } // GetInputsInRadius retrieves input resource flows within a geographic radius func (r *ResourceFlowRepository) GetInputsInRadius(ctx context.Context, lat, lng, radiusKm float64, resType domain.ResourceType) ([]*domain.ResourceFlow, error) { var flows []*domain.ResourceFlow dialector := r.DB().Dialector.Name() if dialector == "postgres" { query := ` SELECT rf.* FROM resource_flows rf JOIN sites s ON rf.site_id = s.id WHERE rf.direction = 'input' AND rf.type = ? AND s.latitude IS NOT NULL AND s.longitude IS NOT NULL AND ( 6371 * acos( cos(radians(?)) * cos(radians(s.latitude)) * cos(radians(s.longitude) - radians(?)) + sin(radians(?)) * sin(radians(s.latitude)) ) ) <= ? ` result := r.DB().WithContext(ctx).Raw(query, resType, lat, lng, lat, radiusKm).Scan(&flows) if result.Error != nil { return nil, result.Error } } else { // Fallback to simple bounding box for SQLite query := ` SELECT rf.* FROM resource_flows rf JOIN sites s ON rf.site_id = s.id WHERE rf.direction = 'input' AND rf.type = ? AND s.latitude IS NOT NULL AND s.longitude IS NOT NULL AND abs(s.latitude - ?) <= 0.09 AND abs(s.longitude - ?) <= 0.15 ` result := r.DB().WithContext(ctx).Raw(query, resType, lat, lng).Scan(&flows) if result.Error != nil { return nil, result.Error } } return flows, nil }