Skip to main content

lemonaid/
lib.rs

1mod entities;
2mod error;
3
4// Re-export types for public API
5pub use entities::access::{
6    EphemerisPoint, EphemerisRequest, EphemerisResponse, FOVAccessRequest, FOVAccessResponse,
7    GeoAccessQuery, GeoAccessResult, GroundStationAccessToSatelliteRequest, HorizonAccess,
8    LocationAccess, LocationWaypoint, SatelliteAccessToGroundstationRequest,
9    SatellitesToLocationRequest, SensorFrame, TrackingParameters,
10};
11pub use entities::account::{
12    AddGroupMemberRequest, GroupMember, UpdatePreferencesRequest, UserAccount, UserPreferences,
13};
14pub use entities::alert_subscription::{
15    AlertSubscription, AlertType, CreateAlertSubscriptionRequest, TargetType,
16    UpdateAlertSubscriptionRequest,
17};
18pub use entities::antenna::Antenna;
19pub use entities::auth::{
20    CreatePersonalAccessTokenRequest, CreatePersonalAccessTokenResponse, PersonalAccessToken,
21    PersonalAccessTokenListResponse,
22};
23pub use entities::collection_request::{
24    CollectionRequest, CollectionRequestType, CreateCollectionRequestRequest,
25};
26pub use entities::elset::{
27    CreateElsetRequest, Elset, ElsetCount, ElsetHistoryQuery, GeoScatterPoint, LeoScatterPoint,
28};
29pub use entities::filter::{Filter, FilterExpandRequest, FilterExpandResponse};
30pub use entities::groundstation::{Groundstation, GroundstationCreateRequest};
31pub use entities::image::{
32    ImageData, ImageDataRequest, ImageListQuery, ImageStatus, ImageUploadRequest,
33    ImageUploadResponse,
34};
35pub use entities::maneuver::{
36    CreateManeuverRequest, Maneuver, ManeuverListQuery, UpdateManeuverRequest,
37};
38pub use entities::observation::{
39    CreateOpticalObservationRequest, ObservationCount, ObservationQuery, OpticalObservation,
40};
41pub use entities::orbit_determination::{ODObservation, ODRequest, ODResult};
42pub use entities::rf_observation::{CreateRFCaptureRequest, RFCapture, RFCaptureSummary};
43pub use entities::satellite::{
44    CloseApproach, CountryCount, GroundTrackPoint, ObservationBounds, ObservationResidual,
45    OrbitalElements, RelativeState, ResidualResult, ResidualsRequest, Satellite, SatelliteListQuery,
46    SatelliteOverview, SatellitePageResponse, SatellitePaginatedResponse,
47};
48pub use entities::satellite_group::{
49    CreateSatelliteGroupRequest, SatelliteGroup, SatelliteGroupMembersRequest,
50    UpdateSatelliteGroupRequest,
51};
52pub use entities::task::{CreateTaskRequest, Task, TaskStatus, TaskUpdateRequest};
53pub use entities::telescope::Telescope;
54pub use entities::weather::{
55    CurrentWeather, MinutelyForecast, WeatherCondition, WeatherQuery, WeatherResponse,
56};
57pub use error::LemonaidError;
58
59pub struct CitraClient {
60    base_url: String,
61    api_key: String,
62    client: reqwest::Client,
63}
64
65impl CitraClient {
66    pub fn new(api_key: &str, dev: bool) -> Self {
67        if !dev {
68            return CitraClient {
69                base_url: "https://api.citra.space/".to_string(),
70                api_key: api_key.to_string(),
71                client: reqwest::Client::new(),
72            };
73        }
74        CitraClient {
75            base_url: "https://dev.api.citra.space/".to_string(),
76            api_key: api_key.to_string(),
77            client: reqwest::Client::new(),
78        }
79    }
80
81    /// Helper method to check response status and return appropriate error
82    async fn check_response(
83        &self,
84        response: reqwest::Response,
85    ) -> Result<reqwest::Response, LemonaidError> {
86        let status = response.status();
87        if status.is_success() {
88            Ok(response)
89        } else {
90            let message = response
91                .text()
92                .await
93                .unwrap_or_else(|_| "Unknown error".to_string());
94            Err(LemonaidError::Api { status, message })
95        }
96    }
97
98    // ==================== TELESCOPE ENDPOINTS ====================
99
100    pub async fn get_telescope(&self, telescope_id: &str) -> Result<Telescope, LemonaidError> {
101        let url = format!("{}telescopes/{}", self.base_url, telescope_id);
102        let response = self
103            .client
104            .get(&url)
105            .header("Authorization", format!("Bearer {}", self.api_key))
106            .send()
107            .await?;
108        let response = self.check_response(response).await?;
109        let telescope = response.json::<Telescope>().await?;
110        Ok(telescope)
111    }
112
113    pub async fn list_telescopes(&self) -> Result<Vec<Telescope>, LemonaidError> {
114        let url = format!("{}telescopes", self.base_url);
115        let response = self
116            .client
117            .get(&url)
118            .header("Authorization", format!("Bearer {}", self.api_key))
119            .send()
120            .await?;
121        let response = self.check_response(response).await?;
122        let telescopes = response.json::<Vec<Telescope>>().await?;
123        Ok(telescopes)
124    }
125
126    pub async fn list_my_telescopes(&self) -> Result<Vec<Telescope>, LemonaidError> {
127        let url = format!("{}my/telescopes", self.base_url);
128        let response = self
129            .client
130            .get(&url)
131            .header("Authorization", format!("Bearer {}", self.api_key))
132            .send()
133            .await?;
134        let response = self.check_response(response).await?;
135        let telescopes = response.json::<Vec<Telescope>>().await?;
136        Ok(telescopes)
137    }
138
139    pub async fn create_telescope(
140        &self,
141        telescope: &Telescope,
142    ) -> Result<Telescope, LemonaidError> {
143        let url = format!("{}telescopes", self.base_url);
144        let response = self
145            .client
146            .post(&url)
147            .header("Authorization", format!("Bearer {}", self.api_key))
148            .json(&vec![telescope])
149            .send()
150            .await?;
151        let response = self.check_response(response).await?;
152        let telescopes = response.json::<Vec<Telescope>>().await?;
153        Ok(telescopes.into_iter().next().unwrap())
154    }
155
156    pub async fn delete_telescope(&self, telescope_id: &str) -> Result<(), LemonaidError> {
157        let url = format!("{}telescopes", self.base_url);
158        let response = self
159            .client
160            .delete(&url)
161            .header("Authorization", format!("Bearer {}", self.api_key))
162            .json(&vec![telescope_id])
163            .send()
164            .await?;
165        self.check_response(response).await?;
166        Ok(())
167    }
168
169    pub async fn update_telescope(
170        &self,
171        telescope: &Telescope,
172    ) -> Result<Telescope, LemonaidError> {
173        let url = format!("{}telescopes", self.base_url);
174        let response = self
175            .client
176            .put(&url)
177            .header("Authorization", format!("Bearer {}", self.api_key))
178            .json(&vec![telescope])
179            .send()
180            .await?;
181        let response = self.check_response(response).await?;
182        let telescopes = response.json::<Vec<Telescope>>().await?;
183        Ok(telescopes.into_iter().next().unwrap())
184    }
185
186    pub async fn list_tasks_for_telescope(
187        &self,
188        telescope_id: &str,
189    ) -> Result<Vec<Task>, LemonaidError> {
190        let url = format!("{}telescopes/{}/tasks", self.base_url, telescope_id);
191        let response = self
192            .client
193            .get(&url)
194            .header("Authorization", format!("Bearer {}", self.api_key))
195            .send()
196            .await?;
197        let response = self.check_response(response).await?;
198        let tasks = response.json::<Vec<Task>>().await?;
199        Ok(tasks)
200    }
201
202    pub async fn get_telescope_tasks_by_status(
203        &self,
204        telescope_id: &str,
205        statuses: Vec<TaskStatus>,
206    ) -> Result<Vec<Task>, LemonaidError> {
207        let status_params: Vec<String> = statuses
208            .iter()
209            .map(|s| format!("statuses={:?}", s))
210            .collect();
211        let query_string = status_params.join("&");
212        let url = format!(
213            "{}telescopes/{}/tasks?{}",
214            self.base_url, telescope_id, query_string
215        );
216        let response = self
217            .client
218            .get(&url)
219            .header("Authorization", format!("Bearer {}", self.api_key))
220            .send()
221            .await?;
222        let response = self.check_response(response).await?;
223        let tasks = response.json::<Vec<Task>>().await?;
224        Ok(tasks)
225    }
226
227    pub async fn list_images_for_telescope(
228        &self,
229        telescope_id: &str,
230        query: Option<&ImageListQuery>,
231    ) -> Result<Vec<ImageStatus>, LemonaidError> {
232        let mut url = format!("{}telescopes/{}/images", self.base_url, telescope_id);
233        if let Some(q) = query {
234            let mut params = Vec::new();
235            if let Some(offset) = q.offset {
236                params.push(format!("offset={}", offset));
237            }
238            if let Some(limit) = q.limit {
239                params.push(format!("limit={}", limit));
240            }
241            if let Some(ref status) = q.status {
242                params.push(format!("status={}", status));
243            }
244            if !params.is_empty() {
245                url = format!("{}?{}", url, params.join("&"));
246            }
247        }
248        let response = self
249            .client
250            .get(&url)
251            .header("Authorization", format!("Bearer {}", self.api_key))
252            .send()
253            .await?;
254        let response = self.check_response(response).await?;
255        let images = response.json::<Vec<ImageStatus>>().await?;
256        Ok(images)
257    }
258
259    // ==================== GROUND STATION ENDPOINTS ====================
260
261    pub async fn get_groundstation(
262        &self,
263        groundstation_id: &str,
264    ) -> Result<Groundstation, LemonaidError> {
265        let url = format!("{}ground-stations/{}", self.base_url, groundstation_id);
266        let response = self
267            .client
268            .get(&url)
269            .header("Authorization", format!("Bearer {}", self.api_key))
270            .send()
271            .await?;
272        let response = self.check_response(response).await?;
273        let groundstation = response.json::<Groundstation>().await?;
274        Ok(groundstation)
275    }
276
277    pub async fn list_groundstations(&self) -> Result<Vec<Groundstation>, LemonaidError> {
278        let url = format!("{}ground-stations", self.base_url);
279        let response = self
280            .client
281            .get(&url)
282            .header("Authorization", format!("Bearer {}", self.api_key))
283            .send()
284            .await?;
285        let response = self.check_response(response).await?;
286        let list_response = response
287            .json::<entities::groundstation::GroundstationListResponse>()
288            .await?;
289        Ok(list_response.ground_stations)
290    }
291
292    pub async fn list_my_groundstations(&self) -> Result<Vec<Groundstation>, LemonaidError> {
293        let url = format!("{}my/ground-stations", self.base_url);
294        let response = self
295            .client
296            .get(&url)
297            .header("Authorization", format!("Bearer {}", self.api_key))
298            .send()
299            .await?;
300        let response = self.check_response(response).await?;
301        let list_response = response
302            .json::<entities::groundstation::GroundstationListResponse>()
303            .await?;
304        Ok(list_response.ground_stations)
305    }
306
307    pub async fn create_groundstation(
308        &self,
309        groundstation: &GroundstationCreateRequest,
310    ) -> Result<Groundstation, LemonaidError> {
311        let url = format!("{}ground-stations", self.base_url);
312        let response = self
313            .client
314            .post(&url)
315            .header("Authorization", format!("Bearer {}", self.api_key))
316            .json(groundstation)
317            .send()
318            .await?;
319        let response = self.check_response(response).await?;
320        let created = response.json::<Groundstation>().await?;
321        Ok(created)
322    }
323
324    pub async fn delete_groundstation(&self, groundstation_id: &str) -> Result<(), LemonaidError> {
325        let url = format!("{}ground-stations/{}", self.base_url, groundstation_id);
326        let response = self
327            .client
328            .delete(&url)
329            .header("Authorization", format!("Bearer {}", self.api_key))
330            .send()
331            .await?;
332        self.check_response(response).await?;
333        Ok(())
334    }
335
336    pub async fn update_groundstation(
337        &self,
338        groundstation_id: &str,
339        groundstation: &GroundstationCreateRequest,
340    ) -> Result<Groundstation, LemonaidError> {
341        let url = format!("{}ground-stations/{}", self.base_url, groundstation_id);
342        let response = self
343            .client
344            .put(&url)
345            .header("Authorization", format!("Bearer {}", self.api_key))
346            .json(groundstation)
347            .send()
348            .await?;
349        let response = self.check_response(response).await?;
350        let groundstation = response.json::<Groundstation>().await?;
351        Ok(groundstation)
352    }
353
354    pub async fn list_telescopes_for_groundstation(
355        &self,
356        groundstation_id: &str,
357    ) -> Result<Vec<Telescope>, LemonaidError> {
358        let url = format!(
359            "{}ground-stations/{}/telescopes",
360            self.base_url, groundstation_id
361        );
362        let response = self
363            .client
364            .get(&url)
365            .header("Authorization", format!("Bearer {}", self.api_key))
366            .send()
367            .await?;
368        let response = self.check_response(response).await?;
369        let telescopes = response.json::<Vec<Telescope>>().await?;
370        Ok(telescopes)
371    }
372
373    pub async fn list_antennas_for_groundstation(
374        &self,
375        groundstation_id: &str,
376    ) -> Result<Vec<Antenna>, LemonaidError> {
377        let url = format!(
378            "{}ground-stations/{}/antennas",
379            self.base_url, groundstation_id
380        );
381        let response = self
382            .client
383            .get(&url)
384            .header("Authorization", format!("Bearer {}", self.api_key))
385            .send()
386            .await?;
387        let response = self.check_response(response).await?;
388        let antennas = response.json::<Vec<Antenna>>().await?;
389        Ok(antennas)
390    }
391
392    // ==================== ANTENNA ENDPOINTS ====================
393
394    pub async fn list_antennas(&self) -> Result<Vec<Antenna>, LemonaidError> {
395        let url = format!("{}antennas", self.base_url);
396        let response = self
397            .client
398            .get(&url)
399            .header("Authorization", format!("Bearer {}", self.api_key))
400            .send()
401            .await?;
402        let response = self.check_response(response).await?;
403        let antennas = response.json::<Vec<Antenna>>().await?;
404        Ok(antennas)
405    }
406
407    pub async fn list_my_antennas(&self) -> Result<Vec<Antenna>, LemonaidError> {
408        let url = format!("{}my/antennas", self.base_url);
409        let response = self
410            .client
411            .get(&url)
412            .header("Authorization", format!("Bearer {}", self.api_key))
413            .send()
414            .await?;
415        let response = self.check_response(response).await?;
416        let antennas = response.json::<Vec<Antenna>>().await?;
417        Ok(antennas)
418    }
419
420    pub async fn get_antenna(&self, antenna_id: &str) -> Result<Antenna, LemonaidError> {
421        let url = format!("{}antennas/{}", self.base_url, antenna_id);
422        let response = self
423            .client
424            .get(&url)
425            .header("Authorization", format!("Bearer {}", self.api_key))
426            .send()
427            .await?;
428        let response = self.check_response(response).await?;
429        let antenna = response.json::<Antenna>().await?;
430        Ok(antenna)
431    }
432
433    pub async fn create_antenna(&self, antenna: &Antenna) -> Result<Antenna, LemonaidError> {
434        let url = format!("{}antennas", self.base_url);
435        let response = self
436            .client
437            .post(&url)
438            .header("Authorization", format!("Bearer {}", self.api_key))
439            .json(&vec![antenna])
440            .send()
441            .await?;
442        let response = self.check_response(response).await?;
443        let antennas = response.json::<Vec<Antenna>>().await?;
444        Ok(antennas.into_iter().next().unwrap())
445    }
446
447    pub async fn delete_antenna(&self, antenna_id: &str) -> Result<(), LemonaidError> {
448        let url = format!("{}antennas", self.base_url);
449        let response = self
450            .client
451            .delete(&url)
452            .header("Authorization", format!("Bearer {}", self.api_key))
453            .json(&vec![antenna_id])
454            .send()
455            .await?;
456        self.check_response(response).await?;
457        Ok(())
458    }
459
460    pub async fn update_antenna(&self, antenna: &Antenna) -> Result<Antenna, LemonaidError> {
461        let url = format!("{}antennas", self.base_url);
462        let response = self
463            .client
464            .put(&url)
465            .header("Authorization", format!("Bearer {}", self.api_key))
466            .json(&vec![antenna])
467            .send()
468            .await?;
469        let response = self.check_response(response).await?;
470        let antennas = response.json::<Vec<Antenna>>().await?;
471        Ok(antennas.into_iter().next().unwrap())
472    }
473
474    pub async fn list_tasks_for_antenna(
475        &self,
476        antenna_id: &str,
477    ) -> Result<Vec<Task>, LemonaidError> {
478        let url = format!("{}antennas/{}/tasks", self.base_url, antenna_id);
479        let response = self
480            .client
481            .get(&url)
482            .header("Authorization", format!("Bearer {}", self.api_key))
483            .send()
484            .await?;
485        let response = self.check_response(response).await?;
486        let tasks = response.json::<Vec<Task>>().await?;
487        Ok(tasks)
488    }
489
490    pub async fn get_antenna_tasks_by_status(
491        &self,
492        antenna_id: &str,
493        statuses: Vec<TaskStatus>,
494    ) -> Result<Vec<Task>, LemonaidError> {
495        let status_params: Vec<String> = statuses
496            .iter()
497            .map(|s| format!("statuses={:?}", s))
498            .collect();
499        let query_string = status_params.join("&");
500        let url = format!(
501            "{}antennas/{}/tasks?{}",
502            self.base_url, antenna_id, query_string
503        );
504        let response = self
505            .client
506            .get(&url)
507            .header("Authorization", format!("Bearer {}", self.api_key))
508            .send()
509            .await?;
510        let response = self.check_response(response).await?;
511        let tasks = response.json::<Vec<Task>>().await?;
512        Ok(tasks)
513    }
514
515    // ==================== TASK ENDPOINTS ====================
516
517    pub async fn create_task(&self, task: &CreateTaskRequest) -> Result<Task, LemonaidError> {
518        let url = format!("{}tasks", self.base_url);
519        let response = self
520            .client
521            .post(&url)
522            .header("Authorization", format!("Bearer {}", self.api_key))
523            .json(task)
524            .send()
525            .await?;
526        let response = self.check_response(response).await?;
527        let created_task = response.json::<Task>().await?;
528        Ok(created_task)
529    }
530
531    pub async fn update_task(&self, task: &TaskUpdateRequest) -> Result<Task, LemonaidError> {
532        let url = format!("{}tasks/{}", self.base_url, task.id);
533        let response = self
534            .client
535            .put(&url)
536            .header("Authorization", format!("Bearer {}", self.api_key))
537            .json(task)
538            .send()
539            .await?;
540        let response = self.check_response(response).await?;
541        let updated_task = response.json::<Task>().await?;
542        Ok(updated_task)
543    }
544
545    pub async fn list_images_for_task(
546        &self,
547        task_id: &str,
548    ) -> Result<Vec<ImageStatus>, LemonaidError> {
549        let url = format!("{}tasks/{}/images", self.base_url, task_id);
550        let response = self
551            .client
552            .get(&url)
553            .header("Authorization", format!("Bearer {}", self.api_key))
554            .send()
555            .await?;
556        let response = self.check_response(response).await?;
557        let images = response.json::<Vec<ImageStatus>>().await?;
558        Ok(images)
559    }
560
561    // ==================== ACCESS ENDPOINTS ====================
562
563    pub async fn solve_access_for_groundstation(
564        &self,
565        access_request: &SatelliteAccessToGroundstationRequest,
566    ) -> Result<Vec<HorizonAccess>, LemonaidError> {
567        let url = format!(
568            "{}access/window/satellites_to_ground_station",
569            self.base_url
570        );
571        let response = self
572            .client
573            .post(&url)
574            .header("Authorization", format!("Bearer {}", self.api_key))
575            .json(access_request)
576            .send()
577            .await?;
578        let response = self.check_response(response).await?;
579        let accesses = response.json::<Vec<HorizonAccess>>().await?;
580        Ok(accesses)
581    }
582
583    pub async fn solve_access_groundstations_to_satellite(
584        &self,
585        access_request: &GroundStationAccessToSatelliteRequest,
586    ) -> Result<Vec<HorizonAccess>, LemonaidError> {
587        let url = format!(
588            "{}access/window/ground_stations_to_satellite",
589            self.base_url
590        );
591        let response = self
592            .client
593            .post(&url)
594            .header("Authorization", format!("Bearer {}", self.api_key))
595            .json(access_request)
596            .send()
597            .await?;
598        let response = self.check_response(response).await?;
599        let accesses = response.json::<Vec<HorizonAccess>>().await?;
600        Ok(accesses)
601    }
602
603    pub async fn solve_access_satellites_to_location(
604        &self,
605        access_request: &SatellitesToLocationRequest,
606    ) -> Result<Vec<LocationAccess>, LemonaidError> {
607        let url = format!("{}access/window/satellitesToLocation", self.base_url);
608        let response = self
609            .client
610            .post(&url)
611            .header("Authorization", format!("Bearer {}", self.api_key))
612            .json(access_request)
613            .send()
614            .await?;
615        let response = self.check_response(response).await?;
616        let accesses = response.json::<Vec<LocationAccess>>().await?;
617        Ok(accesses)
618    }
619
620    pub async fn solve_fov_access(
621        &self,
622        fov_request: &FOVAccessRequest,
623    ) -> Result<Vec<FOVAccessResponse>, LemonaidError> {
624        let url = format!("{}access/fov", self.base_url);
625        let response = self
626            .client
627            .post(&url)
628            .header("Authorization", format!("Bearer {}", self.api_key))
629            .json(fov_request)
630            .send()
631            .await?;
632        let response = self.check_response(response).await?;
633        let fov_responses = response.json::<Vec<FOVAccessResponse>>().await?;
634        Ok(fov_responses)
635    }
636
637    pub async fn get_geo_access(
638        &self,
639        query: &GeoAccessQuery,
640    ) -> Result<Vec<GeoAccessResult>, LemonaidError> {
641        let mut params = Vec::new();
642        if let Some(min_lon) = query.min_longitude_deg {
643            params.push(format!("minLongitude={}", min_lon));
644        }
645        if let Some(max_lon) = query.max_longitude_deg {
646            params.push(format!("maxLongitude={}", max_lon));
647        }
648        if let Some(min_sma) = query.min_semi_major_axis_km {
649            params.push(format!("minSemiMajorAxis={}", min_sma));
650        }
651        if let Some(max_sma) = query.max_semi_major_axis_km {
652            params.push(format!("maxSemiMajorAxis={}", max_sma));
653        }
654        if let Some(max_inc) = query.max_inclination_deg {
655            params.push(format!("maxInclination={}", max_inc));
656        }
657        let url = if params.is_empty() {
658            format!("{}access/geo", self.base_url)
659        } else {
660            format!("{}access/geo?{}", self.base_url, params.join("&"))
661        };
662        let response = self
663            .client
664            .get(&url)
665            .header("Authorization", format!("Bearer {}", self.api_key))
666            .send()
667            .await?;
668        let response = self.check_response(response).await?;
669        let results = response.json::<Vec<GeoAccessResult>>().await?;
670        Ok(results)
671    }
672
673    pub async fn generate_ephemeris(
674        &self,
675        request: &EphemerisRequest,
676    ) -> Result<EphemerisResponse, LemonaidError> {
677        let url = format!("{}access/ephemeris", self.base_url);
678        let response = self
679            .client
680            .post(&url)
681            .header("Authorization", format!("Bearer {}", self.api_key))
682            .json(request)
683            .send()
684            .await?;
685        let response = self.check_response(response).await?;
686        let ephemeris = response.json::<EphemerisResponse>().await?;
687        Ok(ephemeris)
688    }
689
690    // ==================== RF CAPTURE ENDPOINTS ====================
691
692    pub async fn create_rf_capture(
693        &self,
694        rf_capture_request: &CreateRFCaptureRequest,
695    ) -> Result<RFCapture, LemonaidError> {
696        let url = format!("{}rf-captures", self.base_url);
697        let response = self
698            .client
699            .post(&url)
700            .header("Authorization", format!("Bearer {}", self.api_key))
701            .json(rf_capture_request)
702            .send()
703            .await?;
704        let response = self.check_response(response).await?;
705        let rf_capture = response.json::<RFCapture>().await?;
706        Ok(rf_capture)
707    }
708
709    pub async fn get_rf_capture(&self, rf_capture_id: &str) -> Result<RFCapture, LemonaidError> {
710        let url = format!("{}rf-captures/{}", self.base_url, rf_capture_id);
711        let response = self
712            .client
713            .get(&url)
714            .header("Authorization", format!("Bearer {}", self.api_key))
715            .send()
716            .await?;
717        let response = self.check_response(response).await?;
718        let rf_capture = response.json::<RFCapture>().await?;
719        Ok(rf_capture)
720    }
721
722    pub async fn list_rf_captures_for_antenna(
723        &self,
724        antenna_id: &str,
725    ) -> Result<Vec<RFCaptureSummary>, LemonaidError> {
726        let url = format!("{}antennas/{}/rf-captures", self.base_url, antenna_id);
727        let response = self
728            .client
729            .get(&url)
730            .header("Authorization", format!("Bearer {}", self.api_key))
731            .send()
732            .await?;
733        let response = self.check_response(response).await?;
734        let rf_captures = response.json::<Vec<RFCaptureSummary>>().await?;
735        Ok(rf_captures)
736    }
737
738    pub async fn list_rf_captures_for_task(
739        &self,
740        task_id: &str,
741    ) -> Result<Vec<RFCaptureSummary>, LemonaidError> {
742        let url = format!("{}tasks/{}/rf-captures", self.base_url, task_id);
743        let response = self
744            .client
745            .get(&url)
746            .header("Authorization", format!("Bearer {}", self.api_key))
747            .send()
748            .await?;
749        let response = self.check_response(response).await?;
750        let rf_captures = response.json::<Vec<RFCaptureSummary>>().await?;
751        Ok(rf_captures)
752    }
753
754    pub async fn list_rf_captures_for_satellite(
755        &self,
756        satellite_id: &str,
757    ) -> Result<Vec<RFCaptureSummary>, LemonaidError> {
758        let url = format!("{}satellites/{}/rf-captures", self.base_url, satellite_id);
759        let response = self
760            .client
761            .get(&url)
762            .header("Authorization", format!("Bearer {}", self.api_key))
763            .send()
764            .await?;
765        let response = self.check_response(response).await?;
766        let rf_captures = response.json::<Vec<RFCaptureSummary>>().await?;
767        Ok(rf_captures)
768    }
769
770    // ==================== SATELLITE ENDPOINTS ====================
771
772    pub async fn list_satellites(
773        &self,
774        query: Option<&SatelliteListQuery>,
775    ) -> Result<SatellitePageResponse, LemonaidError> {
776        let mut url = format!("{}satellites", self.base_url);
777        if let Some(q) = query {
778            let mut params = Vec::new();
779            if let Some(ref ids) = q.ids {
780                for id in ids {
781                    params.push(format!("ids={}", id));
782                }
783            }
784            if let Some(ref search) = q.search {
785                params.push(format!("search={}", search));
786            }
787            if let Some(ref country) = q.country {
788                params.push(format!("country={}", country));
789            }
790            if let Some(ref object_type) = q.object_type {
791                params.push(format!("objectType={}", object_type));
792            }
793            if let Some(include_decayed) = q.include_decayed {
794                params.push(format!("includeDecayed={}", include_decayed));
795            }
796            if let Some(ref sort_by) = q.sort_by {
797                params.push(format!("sortBy={}", sort_by));
798            }
799            if let Some(ref sort_order) = q.sort_order {
800                params.push(format!("sortOrder={}", sort_order));
801            }
802            if let Some(offset) = q.offset {
803                params.push(format!("offset={}", offset));
804            }
805            if let Some(limit) = q.limit {
806                params.push(format!("limit={}", limit));
807            }
808            if !params.is_empty() {
809                url = format!("{}?{}", url, params.join("&"));
810            }
811        }
812        let response = self
813            .client
814            .get(&url)
815            .header("Authorization", format!("Bearer {}", self.api_key))
816            .send()
817            .await?;
818        let response = self.check_response(response).await?;
819        let page_response = response.json::<SatellitePageResponse>().await?;
820        Ok(page_response)
821    }
822
823    pub async fn get_satellite(&self, satellite_id: &str) -> Result<Satellite, LemonaidError> {
824        let url = format!("{}satellites/{}", self.base_url, satellite_id);
825        let response = self
826            .client
827            .get(&url)
828            .header("Authorization", format!("Bearer {}", self.api_key))
829            .send()
830            .await?;
831        let response = self.check_response(response).await?;
832        let satellite = response.json::<Satellite>().await?;
833        Ok(satellite)
834    }
835
836    pub async fn get_satellites_overview(&self) -> Result<SatelliteOverview, LemonaidError> {
837        let url = format!("{}satellites/overview", self.base_url);
838        let response = self
839            .client
840            .get(&url)
841            .header("Authorization", format!("Bearer {}", self.api_key))
842            .send()
843            .await?;
844        let response = self.check_response(response).await?;
845        let overview = response.json::<SatelliteOverview>().await?;
846        Ok(overview)
847    }
848
849    pub async fn get_satellite_countries(&self) -> Result<Vec<CountryCount>, LemonaidError> {
850        let url = format!("{}satellites/countries", self.base_url);
851        let response = self
852            .client
853            .get(&url)
854            .header("Authorization", format!("Bearer {}", self.api_key))
855            .send()
856            .await?;
857        let response = self.check_response(response).await?;
858        let countries = response.json::<Vec<CountryCount>>().await?;
859        Ok(countries)
860    }
861
862    pub async fn get_satellites_page(
863        &self,
864        offset: i64,
865        limit: i64,
866    ) -> Result<SatellitePaginatedResponse, LemonaidError> {
867        let url = format!(
868            "{}satellites/page?offset={}&limit={}",
869            self.base_url, offset, limit
870        );
871        let response = self
872            .client
873            .get(&url)
874            .header("Authorization", format!("Bearer {}", self.api_key))
875            .send()
876            .await?;
877        let response = self.check_response(response).await?;
878        let page = response.json::<SatellitePaginatedResponse>().await?;
879        Ok(page)
880    }
881
882    pub async fn list_tasks_for_satellite(
883        &self,
884        satellite_id: &str,
885    ) -> Result<Vec<Task>, LemonaidError> {
886        let url = format!("{}satellites/{}/tasks", self.base_url, satellite_id);
887        let response = self
888            .client
889            .get(&url)
890            .header("Authorization", format!("Bearer {}", self.api_key))
891            .send()
892            .await?;
893        let response = self.check_response(response).await?;
894        let tasks = response.json::<Vec<Task>>().await?;
895        Ok(tasks)
896    }
897
898    pub async fn calculate_residuals(
899        &self,
900        satellite_id: &str,
901        request: &ResidualsRequest,
902    ) -> Result<Vec<ResidualResult>, LemonaidError> {
903        let url = format!("{}satellites/{}/residuals", self.base_url, satellite_id);
904        let response = self
905            .client
906            .post(&url)
907            .header("Authorization", format!("Bearer {}", self.api_key))
908            .json(request)
909            .send()
910            .await?;
911        let response = self.check_response(response).await?;
912        let residuals = response.json::<Vec<ResidualResult>>().await?;
913        Ok(residuals)
914    }
915
916    pub async fn get_close_approaches(
917        &self,
918        satellite_id: &str,
919    ) -> Result<Vec<CloseApproach>, LemonaidError> {
920        let url = format!("{}satellites/{}/close-approaches", self.base_url, satellite_id);
921        let response = self
922            .client
923            .get(&url)
924            .header("Authorization", format!("Bearer {}", self.api_key))
925            .send()
926            .await?;
927        let response = self.check_response(response).await?;
928        let approaches = response.json::<Vec<CloseApproach>>().await?;
929        Ok(approaches)
930    }
931
932    pub async fn get_relative_state(
933        &self,
934        satellite_id: &str,
935        other_satellite_id: &str,
936    ) -> Result<Vec<RelativeState>, LemonaidError> {
937        let url = format!(
938            "{}satellites/{}/relative/{}",
939            self.base_url, satellite_id, other_satellite_id
940        );
941        let response = self
942            .client
943            .get(&url)
944            .header("Authorization", format!("Bearer {}", self.api_key))
945            .send()
946            .await?;
947        let response = self.check_response(response).await?;
948        let states = response.json::<Vec<RelativeState>>().await?;
949        Ok(states)
950    }
951
952    pub async fn get_satellite_ground_track(
953        &self,
954        satellite_id: &str,
955    ) -> Result<Vec<GroundTrackPoint>, LemonaidError> {
956        let url = format!("{}satellites/{}/ground-track", self.base_url, satellite_id);
957        let response = self
958            .client
959            .get(&url)
960            .header("Authorization", format!("Bearer {}", self.api_key))
961            .send()
962            .await?;
963        let response = self.check_response(response).await?;
964        let track = response.json::<Vec<GroundTrackPoint>>().await?;
965        Ok(track)
966    }
967
968    pub async fn get_satellite_observation_bounds(
969        &self,
970        satellite_id: &str,
971    ) -> Result<ObservationBounds, LemonaidError> {
972        let url = format!(
973            "{}satellites/{}/observation-bounds",
974            self.base_url, satellite_id
975        );
976        let response = self
977            .client
978            .get(&url)
979            .header("Authorization", format!("Bearer {}", self.api_key))
980            .send()
981            .await?;
982        let response = self.check_response(response).await?;
983        let bounds = response.json::<ObservationBounds>().await?;
984        Ok(bounds)
985    }
986
987    pub async fn get_satellite_groups_for_satellite(
988        &self,
989        satellite_id: &str,
990    ) -> Result<Vec<SatelliteGroup>, LemonaidError> {
991        let url = format!("{}satellites/{}/groups", self.base_url, satellite_id);
992        let response = self
993            .client
994            .get(&url)
995            .header("Authorization", format!("Bearer {}", self.api_key))
996            .send()
997            .await?;
998        let response = self.check_response(response).await?;
999        let groups = response.json::<Vec<SatelliteGroup>>().await?;
1000        Ok(groups)
1001    }
1002
1003    pub async fn list_images_for_satellite(
1004        &self,
1005        satellite_id: &str,
1006        query: Option<&ImageListQuery>,
1007    ) -> Result<Vec<ImageStatus>, LemonaidError> {
1008        let mut url = format!("{}satellites/{}/images", self.base_url, satellite_id);
1009        if let Some(q) = query {
1010            let mut params = Vec::new();
1011            if let Some(offset) = q.offset {
1012                params.push(format!("offset={}", offset));
1013            }
1014            if let Some(limit) = q.limit {
1015                params.push(format!("limit={}", limit));
1016            }
1017            if !params.is_empty() {
1018                url = format!("{}?{}", url, params.join("&"));
1019            }
1020        }
1021        let response = self
1022            .client
1023            .get(&url)
1024            .header("Authorization", format!("Bearer {}", self.api_key))
1025            .send()
1026            .await?;
1027        let response = self.check_response(response).await?;
1028        let images = response.json::<Vec<ImageStatus>>().await?;
1029        Ok(images)
1030    }
1031
1032    pub async fn list_collection_requests_for_satellite(
1033        &self,
1034        satellite_id: &str,
1035    ) -> Result<Vec<CollectionRequest>, LemonaidError> {
1036        let url = format!(
1037            "{}satellites/{}/collection-requests",
1038            self.base_url, satellite_id
1039        );
1040        let response = self
1041            .client
1042            .get(&url)
1043            .header("Authorization", format!("Bearer {}", self.api_key))
1044            .send()
1045            .await?;
1046        let response = self.check_response(response).await?;
1047        let requests = response.json::<Vec<CollectionRequest>>().await?;
1048        Ok(requests)
1049    }
1050
1051    pub async fn get_satellite_orbital_elements(
1052        &self,
1053        satellite_id: &str,
1054    ) -> Result<Vec<OrbitalElements>, LemonaidError> {
1055        let url = format!(
1056            "{}satellites/{}/orbital-elements",
1057            self.base_url, satellite_id
1058        );
1059        let response = self
1060            .client
1061            .get(&url)
1062            .header("Authorization", format!("Bearer {}", self.api_key))
1063            .send()
1064            .await?;
1065        let response = self.check_response(response).await?;
1066        let elements = response.json::<Vec<OrbitalElements>>().await?;
1067        Ok(elements)
1068    }
1069
1070    // ==================== ELSET ENDPOINTS ====================
1071
1072    pub async fn get_satellite_elsets(
1073        &self,
1074        satellite_id: &str,
1075    ) -> Result<Vec<Elset>, LemonaidError> {
1076        let url = format!("{}satellites/{}/elsets", self.base_url, satellite_id);
1077        let response = self
1078            .client
1079            .get(&url)
1080            .header("Authorization", format!("Bearer {}", self.api_key))
1081            .send()
1082            .await?;
1083        let response = self.check_response(response).await?;
1084        let elsets = response.json::<Vec<Elset>>().await?;
1085        Ok(elsets)
1086    }
1087
1088    pub async fn create_elset(
1089        &self,
1090        satellite_id: &str,
1091        request: &CreateElsetRequest,
1092    ) -> Result<Elset, LemonaidError> {
1093        let url = format!("{}satellites/{}/elsets", self.base_url, satellite_id);
1094        let response = self
1095            .client
1096            .post(&url)
1097            .header("Authorization", format!("Bearer {}", self.api_key))
1098            .json(request)
1099            .send()
1100            .await?;
1101        let response = self.check_response(response).await?;
1102        let elset = response.json::<Elset>().await?;
1103        Ok(elset)
1104    }
1105
1106    pub async fn get_satellite_elset_history(
1107        &self,
1108        satellite_id: &str,
1109        query: Option<&ElsetHistoryQuery>,
1110    ) -> Result<Vec<Elset>, LemonaidError> {
1111        let mut url = format!("{}satellites/{}/elset-history", self.base_url, satellite_id);
1112        if let Some(q) = query {
1113            let mut params = Vec::new();
1114            if let Some(ref start) = q.start {
1115                params.push(format!("start={}", start.to_rfc3339()));
1116            }
1117            if let Some(ref end) = q.end {
1118                params.push(format!("end={}", end.to_rfc3339()));
1119            }
1120            if let Some(ref source) = q.source {
1121                params.push(format!("source={}", source));
1122            }
1123            if let Some(limit) = q.limit {
1124                params.push(format!("limit={}", limit));
1125            }
1126            if !params.is_empty() {
1127                url = format!("{}?{}", url, params.join("&"));
1128            }
1129        }
1130        let response = self
1131            .client
1132            .get(&url)
1133            .header("Authorization", format!("Bearer {}", self.api_key))
1134            .send()
1135            .await?;
1136        let response = self.check_response(response).await?;
1137        let elsets = response.json::<Vec<Elset>>().await?;
1138        Ok(elsets)
1139    }
1140
1141    pub async fn get_latest_elsets(&self, days: Option<i32>) -> Result<Vec<Elset>, LemonaidError> {
1142        let url = match days {
1143            Some(d) => format!("{}elsets/latest?days={}", self.base_url, d),
1144            None => format!("{}elsets/latest", self.base_url),
1145        };
1146        let response = self
1147            .client
1148            .get(&url)
1149            .header("Authorization", format!("Bearer {}", self.api_key))
1150            .send()
1151            .await?;
1152        let response = self.check_response(response).await?;
1153        let elsets = response.json::<Vec<Elset>>().await?;
1154        Ok(elsets)
1155    }
1156
1157    pub async fn get_elset_counts(&self) -> Result<Vec<ElsetCount>, LemonaidError> {
1158        let url = format!("{}elsets/counts", self.base_url);
1159        let response = self
1160            .client
1161            .get(&url)
1162            .header("Authorization", format!("Bearer {}", self.api_key))
1163            .send()
1164            .await?;
1165        let response = self.check_response(response).await?;
1166        let counts = response.json::<Vec<ElsetCount>>().await?;
1167        Ok(counts)
1168    }
1169
1170    pub async fn get_near_geo_scatter(&self) -> Result<Vec<GeoScatterPoint>, LemonaidError> {
1171        let url = format!("{}elsets/near-geo-scatter", self.base_url);
1172        let response = self
1173            .client
1174            .get(&url)
1175            .header("Authorization", format!("Bearer {}", self.api_key))
1176            .send()
1177            .await?;
1178        let response = self.check_response(response).await?;
1179        let scatter = response.json::<Vec<GeoScatterPoint>>().await?;
1180        Ok(scatter)
1181    }
1182
1183    pub async fn get_leo_scatter(
1184        &self,
1185        min_sma_km: Option<f64>,
1186        max_sma_km: Option<f64>,
1187    ) -> Result<Vec<LeoScatterPoint>, LemonaidError> {
1188        let mut params = Vec::new();
1189        if let Some(min) = min_sma_km {
1190            params.push(format!("minSma={}", min));
1191        }
1192        if let Some(max) = max_sma_km {
1193            params.push(format!("maxSma={}", max));
1194        }
1195        let url = if params.is_empty() {
1196            format!("{}elsets/leo-scatter", self.base_url)
1197        } else {
1198            format!("{}elsets/leo-scatter?{}", self.base_url, params.join("&"))
1199        };
1200        let response = self
1201            .client
1202            .get(&url)
1203            .header("Authorization", format!("Bearer {}", self.api_key))
1204            .send()
1205            .await?;
1206        let response = self.check_response(response).await?;
1207        let scatter = response.json::<Vec<LeoScatterPoint>>().await?;
1208        Ok(scatter)
1209    }
1210
1211    pub async fn reject_elset(&self, elset_id: &str) -> Result<(), LemonaidError> {
1212        let url = format!("{}elsets/{}/reject", self.base_url, elset_id);
1213        let response = self
1214            .client
1215            .patch(&url)
1216            .header("Authorization", format!("Bearer {}", self.api_key))
1217            .send()
1218            .await?;
1219        self.check_response(response).await?;
1220        Ok(())
1221    }
1222
1223    // ==================== SATELLITE GROUP ENDPOINTS ====================
1224
1225    pub async fn list_satellite_groups(&self) -> Result<Vec<SatelliteGroup>, LemonaidError> {
1226        let url = format!("{}satellite-groups", self.base_url);
1227        let response = self
1228            .client
1229            .get(&url)
1230            .header("Authorization", format!("Bearer {}", self.api_key))
1231            .send()
1232            .await?;
1233        let response = self.check_response(response).await?;
1234        let groups = response.json::<Vec<SatelliteGroup>>().await?;
1235        Ok(groups)
1236    }
1237
1238    pub async fn list_my_satellite_groups(&self) -> Result<Vec<SatelliteGroup>, LemonaidError> {
1239        let url = format!("{}my/satellite-groups", self.base_url);
1240        let response = self
1241            .client
1242            .get(&url)
1243            .header("Authorization", format!("Bearer {}", self.api_key))
1244            .send()
1245            .await?;
1246        let response = self.check_response(response).await?;
1247        let groups = response.json::<Vec<SatelliteGroup>>().await?;
1248        Ok(groups)
1249    }
1250
1251    pub async fn list_favorite_satellite_groups(
1252        &self,
1253    ) -> Result<Vec<SatelliteGroup>, LemonaidError> {
1254        let url = format!("{}my/satellite-groups/favorites", self.base_url);
1255        let response = self
1256            .client
1257            .get(&url)
1258            .header("Authorization", format!("Bearer {}", self.api_key))
1259            .send()
1260            .await?;
1261        let response = self.check_response(response).await?;
1262        let groups = response.json::<Vec<SatelliteGroup>>().await?;
1263        Ok(groups)
1264    }
1265
1266    pub async fn get_satellite_group(
1267        &self,
1268        group_id: &str,
1269    ) -> Result<SatelliteGroup, LemonaidError> {
1270        let url = format!("{}satellite-groups/{}", self.base_url, group_id);
1271        let response = self
1272            .client
1273            .get(&url)
1274            .header("Authorization", format!("Bearer {}", self.api_key))
1275            .send()
1276            .await?;
1277        let response = self.check_response(response).await?;
1278        let group = response.json::<SatelliteGroup>().await?;
1279        Ok(group)
1280    }
1281
1282    pub async fn create_satellite_group(
1283        &self,
1284        request: &CreateSatelliteGroupRequest,
1285    ) -> Result<String, LemonaidError> {
1286        let url = format!("{}satellite-groups", self.base_url);
1287        let response = self
1288            .client
1289            .post(&url)
1290            .header("Authorization", format!("Bearer {}", self.api_key))
1291            .json(&vec![request])
1292            .send()
1293            .await?;
1294        let response = self.check_response(response).await?;
1295        let ids = response.json::<Vec<String>>().await?;
1296        Ok(ids.into_iter().next().unwrap())
1297    }
1298
1299    pub async fn update_satellite_group(
1300        &self,
1301        request: &UpdateSatelliteGroupRequest,
1302    ) -> Result<String, LemonaidError> {
1303        let url = format!("{}satellite-groups", self.base_url);
1304        let response = self
1305            .client
1306            .put(&url)
1307            .header("Authorization", format!("Bearer {}", self.api_key))
1308            .json(&vec![request])
1309            .send()
1310            .await?;
1311        let response = self.check_response(response).await?;
1312        let ids = response.json::<Vec<String>>().await?;
1313        Ok(ids.into_iter().next().unwrap())
1314    }
1315
1316    pub async fn delete_satellite_group(&self, group_id: &str) -> Result<(), LemonaidError> {
1317        let url = format!("{}satellite-groups/{}", self.base_url, group_id);
1318        let response = self
1319            .client
1320            .delete(&url)
1321            .header("Authorization", format!("Bearer {}", self.api_key))
1322            .send()
1323            .await?;
1324        self.check_response(response).await?;
1325        Ok(())
1326    }
1327
1328    pub async fn get_satellites_in_group(
1329        &self,
1330        group_id: &str,
1331    ) -> Result<Vec<Satellite>, LemonaidError> {
1332        let url = format!("{}satellite-groups/{}/satellites", self.base_url, group_id);
1333        let response = self
1334            .client
1335            .get(&url)
1336            .header("Authorization", format!("Bearer {}", self.api_key))
1337            .send()
1338            .await?;
1339        let response = self.check_response(response).await?;
1340        let satellites = response.json::<Vec<Satellite>>().await?;
1341        Ok(satellites)
1342    }
1343
1344    pub async fn add_satellites_to_group(
1345        &self,
1346        group_id: &str,
1347        request: &SatelliteGroupMembersRequest,
1348    ) -> Result<(), LemonaidError> {
1349        let url = format!("{}satellite-groups/{}/satellites", self.base_url, group_id);
1350        let response = self
1351            .client
1352            .post(&url)
1353            .header("Authorization", format!("Bearer {}", self.api_key))
1354            .json(request)
1355            .send()
1356            .await?;
1357        self.check_response(response).await?;
1358        Ok(())
1359    }
1360
1361    pub async fn remove_satellites_from_group(
1362        &self,
1363        group_id: &str,
1364        request: &SatelliteGroupMembersRequest,
1365    ) -> Result<(), LemonaidError> {
1366        let url = format!("{}satellite-groups/{}/satellites", self.base_url, group_id);
1367        let response = self
1368            .client
1369            .delete(&url)
1370            .header("Authorization", format!("Bearer {}", self.api_key))
1371            .json(request)
1372            .send()
1373            .await?;
1374        self.check_response(response).await?;
1375        Ok(())
1376    }
1377
1378    pub async fn favorite_satellite_group(&self, group_id: &str) -> Result<(), LemonaidError> {
1379        let url = format!("{}satellite-groups/{}/favorite", self.base_url, group_id);
1380        let response = self
1381            .client
1382            .post(&url)
1383            .header("Authorization", format!("Bearer {}", self.api_key))
1384            .send()
1385            .await?;
1386        self.check_response(response).await?;
1387        Ok(())
1388    }
1389
1390    pub async fn unfavorite_satellite_group(&self, group_id: &str) -> Result<(), LemonaidError> {
1391        let url = format!("{}satellite-groups/{}/favorite", self.base_url, group_id);
1392        let response = self
1393            .client
1394            .delete(&url)
1395            .header("Authorization", format!("Bearer {}", self.api_key))
1396            .send()
1397            .await?;
1398        self.check_response(response).await?;
1399        Ok(())
1400    }
1401
1402    // ==================== WEATHER ENDPOINT ====================
1403
1404    pub async fn get_weather(&self, query: &WeatherQuery) -> Result<WeatherResponse, LemonaidError> {
1405        let mut params = vec![
1406            format!("lat={}", query.latitude),
1407            format!("lon={}", query.longitude),
1408        ];
1409        if let Some(ref units) = query.units {
1410            params.push(format!("units={}", units));
1411        }
1412        let url = format!("{}weather?{}", self.base_url, params.join("&"));
1413        let response = self
1414            .client
1415            .get(&url)
1416            .header("Authorization", format!("Bearer {}", self.api_key))
1417            .send()
1418            .await?;
1419        let response = self.check_response(response).await?;
1420        let weather = response.json::<WeatherResponse>().await?;
1421        Ok(weather)
1422    }
1423
1424    // ==================== ACCOUNT ENDPOINTS ====================
1425
1426    pub async fn get_my_account(&self) -> Result<UserAccount, LemonaidError> {
1427        let url = format!("{}my/account", self.base_url);
1428        let response = self
1429            .client
1430            .get(&url)
1431            .header("Authorization", format!("Bearer {}", self.api_key))
1432            .send()
1433            .await?;
1434        let response = self.check_response(response).await?;
1435        let account = response.json::<UserAccount>().await?;
1436        Ok(account)
1437    }
1438
1439    pub async fn update_my_preferences(
1440        &self,
1441        request: &UpdatePreferencesRequest,
1442    ) -> Result<UserPreferences, LemonaidError> {
1443        let url = format!("{}my/preferences", self.base_url);
1444        let response = self
1445            .client
1446            .patch(&url)
1447            .header("Authorization", format!("Bearer {}", self.api_key))
1448            .json(request)
1449            .send()
1450            .await?;
1451        let response = self.check_response(response).await?;
1452        let preferences = response.json::<UserPreferences>().await?;
1453        Ok(preferences)
1454    }
1455
1456    pub async fn list_group_members(&self) -> Result<Vec<GroupMember>, LemonaidError> {
1457        let url = format!("{}my/group/members", self.base_url);
1458        let response = self
1459            .client
1460            .get(&url)
1461            .header("Authorization", format!("Bearer {}", self.api_key))
1462            .send()
1463            .await?;
1464        let response = self.check_response(response).await?;
1465        let members = response.json::<Vec<GroupMember>>().await?;
1466        Ok(members)
1467    }
1468
1469    pub async fn add_group_member(
1470        &self,
1471        request: &AddGroupMemberRequest,
1472    ) -> Result<GroupMember, LemonaidError> {
1473        let url = format!("{}my/group/members", self.base_url);
1474        let response = self
1475            .client
1476            .post(&url)
1477            .header("Authorization", format!("Bearer {}", self.api_key))
1478            .json(request)
1479            .send()
1480            .await?;
1481        let response = self.check_response(response).await?;
1482        let member = response.json::<GroupMember>().await?;
1483        Ok(member)
1484    }
1485
1486    pub async fn remove_group_member(&self, user_id: &str) -> Result<(), LemonaidError> {
1487        let url = format!("{}my/group/members/{}", self.base_url, user_id);
1488        let response = self
1489            .client
1490            .delete(&url)
1491            .header("Authorization", format!("Bearer {}", self.api_key))
1492            .send()
1493            .await?;
1494        self.check_response(response).await?;
1495        Ok(())
1496    }
1497
1498    // ==================== IMAGE ENDPOINTS ====================
1499
1500    pub async fn initiate_image_upload(
1501        &self,
1502        request: &ImageUploadRequest,
1503    ) -> Result<ImageUploadResponse, LemonaidError> {
1504        let url = format!("{}my/images", self.base_url);
1505        let response = self
1506            .client
1507            .post(&url)
1508            .header("Authorization", format!("Bearer {}", self.api_key))
1509            .json(request)
1510            .send()
1511            .await?;
1512        let response = self.check_response(response).await?;
1513        let upload = response.json::<ImageUploadResponse>().await?;
1514        Ok(upload)
1515    }
1516
1517    pub async fn list_my_images(
1518        &self,
1519        query: Option<&ImageListQuery>,
1520    ) -> Result<Vec<ImageStatus>, LemonaidError> {
1521        let mut url = format!("{}my/images", self.base_url);
1522        if let Some(q) = query {
1523            let mut params = Vec::new();
1524            if let Some(offset) = q.offset {
1525                params.push(format!("offset={}", offset));
1526            }
1527            if let Some(limit) = q.limit {
1528                params.push(format!("limit={}", limit));
1529            }
1530            if let Some(ref status) = q.status {
1531                params.push(format!("status={}", status));
1532            }
1533            if !params.is_empty() {
1534                url = format!("{}?{}", url, params.join("&"));
1535            }
1536        }
1537        let response = self
1538            .client
1539            .get(&url)
1540            .header("Authorization", format!("Bearer {}", self.api_key))
1541            .send()
1542            .await?;
1543        let response = self.check_response(response).await?;
1544        let images = response.json::<Vec<ImageStatus>>().await?;
1545        Ok(images)
1546    }
1547
1548    pub async fn get_image_status(&self, upload_id: &str) -> Result<ImageStatus, LemonaidError> {
1549        let url = format!("{}my/images/{}", self.base_url, upload_id);
1550        let response = self
1551            .client
1552            .get(&url)
1553            .header("Authorization", format!("Bearer {}", self.api_key))
1554            .send()
1555            .await?;
1556        let response = self.check_response(response).await?;
1557        let status = response.json::<ImageStatus>().await?;
1558        Ok(status)
1559    }
1560
1561    pub async fn delete_image(&self, upload_id: &str) -> Result<(), LemonaidError> {
1562        let url = format!("{}my/images/{}", self.base_url, upload_id);
1563        let response = self
1564            .client
1565            .delete(&url)
1566            .header("Authorization", format!("Bearer {}", self.api_key))
1567            .send()
1568            .await?;
1569        self.check_response(response).await?;
1570        Ok(())
1571    }
1572
1573    pub async fn get_image_data(
1574        &self,
1575        upload_id: &str,
1576        request: Option<&ImageDataRequest>,
1577    ) -> Result<ImageData, LemonaidError> {
1578        let mut url = format!("{}images/{}/data", self.base_url, upload_id);
1579        if let Some(req) = request {
1580            let mut params = Vec::new();
1581            if let Some(binning) = req.binning {
1582                params.push(format!("binning={}", binning));
1583            }
1584            if let Some(ref contrast) = req.contrast {
1585                params.push(format!("contrast={}", contrast));
1586            }
1587            if !params.is_empty() {
1588                url = format!("{}?{}", url, params.join("&"));
1589            }
1590        }
1591        let response = self
1592            .client
1593            .get(&url)
1594            .header("Authorization", format!("Bearer {}", self.api_key))
1595            .send()
1596            .await?;
1597        let response = self.check_response(response).await?;
1598        let data = response.json::<ImageData>().await?;
1599        Ok(data)
1600    }
1601
1602    // ==================== OBSERVATION ENDPOINTS ====================
1603
1604    pub async fn get_optical_observation_counts(
1605        &self,
1606    ) -> Result<Vec<ObservationCount>, LemonaidError> {
1607        let url = format!("{}observations/optical/counts", self.base_url);
1608        let response = self
1609            .client
1610            .get(&url)
1611            .header("Authorization", format!("Bearer {}", self.api_key))
1612            .send()
1613            .await?;
1614        let response = self.check_response(response).await?;
1615        let counts = response.json::<Vec<ObservationCount>>().await?;
1616        Ok(counts)
1617    }
1618
1619    pub async fn upload_optical_observations(
1620        &self,
1621        observations: &[CreateOpticalObservationRequest],
1622    ) -> Result<Vec<OpticalObservation>, LemonaidError> {
1623        let url = format!("{}observations/optical", self.base_url);
1624        let response = self
1625            .client
1626            .post(&url)
1627            .header("Authorization", format!("Bearer {}", self.api_key))
1628            .json(observations)
1629            .send()
1630            .await?;
1631        let response = self.check_response(response).await?;
1632        let created = response.json::<Vec<OpticalObservation>>().await?;
1633        Ok(created)
1634    }
1635
1636    pub async fn query_optical_observations(
1637        &self,
1638        query: &ObservationQuery,
1639    ) -> Result<Vec<OpticalObservation>, LemonaidError> {
1640        let mut params = Vec::new();
1641        if let Some(ref satellite_id) = query.satellite_id {
1642            params.push(format!("satelliteId={}", satellite_id));
1643        }
1644        if let Some(ref telescope_id) = query.telescope_id {
1645            params.push(format!("telescopeId={}", telescope_id));
1646        }
1647        if let Some(ref start) = query.start {
1648            params.push(format!("start={}", start.to_rfc3339()));
1649        }
1650        if let Some(ref end) = query.end {
1651            params.push(format!("end={}", end.to_rfc3339()));
1652        }
1653        if let Some(offset) = query.offset {
1654            params.push(format!("offset={}", offset));
1655        }
1656        if let Some(limit) = query.limit {
1657            params.push(format!("limit={}", limit));
1658        }
1659        let url = if params.is_empty() {
1660            format!("{}observations/optical", self.base_url)
1661        } else {
1662            format!("{}observations/optical?{}", self.base_url, params.join("&"))
1663        };
1664        let response = self
1665            .client
1666            .get(&url)
1667            .header("Authorization", format!("Bearer {}", self.api_key))
1668            .send()
1669            .await?;
1670        let response = self.check_response(response).await?;
1671        let observations = response.json::<Vec<OpticalObservation>>().await?;
1672        Ok(observations)
1673    }
1674
1675    // ==================== COLLECTION REQUEST ENDPOINTS ====================
1676
1677    pub async fn create_collection_request(
1678        &self,
1679        request: &CreateCollectionRequestRequest,
1680    ) -> Result<CollectionRequest, LemonaidError> {
1681        let url = format!("{}collection-requests", self.base_url);
1682        let response = self
1683            .client
1684            .post(&url)
1685            .header("Authorization", format!("Bearer {}", self.api_key))
1686            .json(request)
1687            .send()
1688            .await?;
1689        let response = self.check_response(response).await?;
1690        let collection_request = response.json::<CollectionRequest>().await?;
1691        Ok(collection_request)
1692    }
1693
1694    // ==================== FILTER ENDPOINTS ====================
1695
1696    pub async fn list_filters(&self) -> Result<Vec<Filter>, LemonaidError> {
1697        let url = format!("{}filters/list", self.base_url);
1698        let response = self
1699            .client
1700            .get(&url)
1701            .header("Authorization", format!("Bearer {}", self.api_key))
1702            .send()
1703            .await?;
1704        let response = self.check_response(response).await?;
1705        let filters = response.json::<Vec<Filter>>().await?;
1706        Ok(filters)
1707    }
1708
1709    pub async fn expand_filters(
1710        &self,
1711        request: &FilterExpandRequest,
1712    ) -> Result<FilterExpandResponse, LemonaidError> {
1713        let url = format!("{}filters/expand", self.base_url);
1714        let response = self
1715            .client
1716            .post(&url)
1717            .header("Authorization", format!("Bearer {}", self.api_key))
1718            .json(request)
1719            .send()
1720            .await?;
1721        let response = self.check_response(response).await?;
1722        let expanded = response.json::<FilterExpandResponse>().await?;
1723        Ok(expanded)
1724    }
1725
1726    // ==================== MANEUVER ENDPOINTS ====================
1727
1728    pub async fn list_maneuvers(
1729        &self,
1730        query: Option<&ManeuverListQuery>,
1731    ) -> Result<Vec<Maneuver>, LemonaidError> {
1732        let mut url = format!("{}maneuvers", self.base_url);
1733        if let Some(q) = query {
1734            let mut params = Vec::new();
1735            if let Some(ref satellite_id) = q.satellite_id {
1736                params.push(format!("satelliteId={}", satellite_id));
1737            }
1738            if let Some(ref status) = q.status {
1739                params.push(format!("status={}", status));
1740            }
1741            if let Some(ref start) = q.start {
1742                params.push(format!("start={}", start.to_rfc3339()));
1743            }
1744            if let Some(ref end) = q.end {
1745                params.push(format!("end={}", end.to_rfc3339()));
1746            }
1747            if let Some(offset) = q.offset {
1748                params.push(format!("offset={}", offset));
1749            }
1750            if let Some(limit) = q.limit {
1751                params.push(format!("limit={}", limit));
1752            }
1753            if !params.is_empty() {
1754                url = format!("{}?{}", url, params.join("&"));
1755            }
1756        }
1757        let response = self
1758            .client
1759            .get(&url)
1760            .header("Authorization", format!("Bearer {}", self.api_key))
1761            .send()
1762            .await?;
1763        let response = self.check_response(response).await?;
1764        let maneuvers = response.json::<Vec<Maneuver>>().await?;
1765        Ok(maneuvers)
1766    }
1767
1768    pub async fn get_maneuver(&self, maneuver_id: &str) -> Result<Maneuver, LemonaidError> {
1769        let url = format!("{}maneuvers/{}", self.base_url, maneuver_id);
1770        let response = self
1771            .client
1772            .get(&url)
1773            .header("Authorization", format!("Bearer {}", self.api_key))
1774            .send()
1775            .await?;
1776        let response = self.check_response(response).await?;
1777        let maneuver = response.json::<Maneuver>().await?;
1778        Ok(maneuver)
1779    }
1780
1781    pub async fn create_maneuver(
1782        &self,
1783        request: &CreateManeuverRequest,
1784    ) -> Result<Maneuver, LemonaidError> {
1785        let url = format!("{}maneuvers", self.base_url);
1786        let response = self
1787            .client
1788            .post(&url)
1789            .header("Authorization", format!("Bearer {}", self.api_key))
1790            .json(request)
1791            .send()
1792            .await?;
1793        let response = self.check_response(response).await?;
1794        let maneuver = response.json::<Maneuver>().await?;
1795        Ok(maneuver)
1796    }
1797
1798    pub async fn update_maneuver(
1799        &self,
1800        maneuver_id: &str,
1801        request: &UpdateManeuverRequest,
1802    ) -> Result<Maneuver, LemonaidError> {
1803        let url = format!("{}maneuvers/{}", self.base_url, maneuver_id);
1804        let response = self
1805            .client
1806            .put(&url)
1807            .header("Authorization", format!("Bearer {}", self.api_key))
1808            .json(request)
1809            .send()
1810            .await?;
1811        let response = self.check_response(response).await?;
1812        let maneuver = response.json::<Maneuver>().await?;
1813        Ok(maneuver)
1814    }
1815
1816    pub async fn list_maneuvers_for_satellite(
1817        &self,
1818        satellite_id: &str,
1819    ) -> Result<Vec<Maneuver>, LemonaidError> {
1820        let url = format!("{}satellites/{}/maneuvers", self.base_url, satellite_id);
1821        let response = self
1822            .client
1823            .get(&url)
1824            .header("Authorization", format!("Bearer {}", self.api_key))
1825            .send()
1826            .await?;
1827        let response = self.check_response(response).await?;
1828        let maneuvers = response.json::<Vec<Maneuver>>().await?;
1829        Ok(maneuvers)
1830    }
1831
1832    // ==================== ALERT SUBSCRIPTION ENDPOINTS ====================
1833
1834    pub async fn list_alert_subscriptions(
1835        &self,
1836    ) -> Result<Vec<AlertSubscription>, LemonaidError> {
1837        let url = format!("{}my/alert-subscriptions", self.base_url);
1838        let response = self
1839            .client
1840            .get(&url)
1841            .header("Authorization", format!("Bearer {}", self.api_key))
1842            .send()
1843            .await?;
1844        let response = self.check_response(response).await?;
1845        let subscriptions = response.json::<Vec<AlertSubscription>>().await?;
1846        Ok(subscriptions)
1847    }
1848
1849    pub async fn get_alert_subscription(
1850        &self,
1851        subscription_id: &str,
1852    ) -> Result<AlertSubscription, LemonaidError> {
1853        let url = format!(
1854            "{}my/alert-subscriptions/{}",
1855            self.base_url, subscription_id
1856        );
1857        let response = self
1858            .client
1859            .get(&url)
1860            .header("Authorization", format!("Bearer {}", self.api_key))
1861            .send()
1862            .await?;
1863        let response = self.check_response(response).await?;
1864        let subscription = response.json::<AlertSubscription>().await?;
1865        Ok(subscription)
1866    }
1867
1868    pub async fn create_alert_subscription(
1869        &self,
1870        request: &CreateAlertSubscriptionRequest,
1871    ) -> Result<AlertSubscription, LemonaidError> {
1872        let url = format!("{}my/alert-subscriptions", self.base_url);
1873        let response = self
1874            .client
1875            .post(&url)
1876            .header("Authorization", format!("Bearer {}", self.api_key))
1877            .json(request)
1878            .send()
1879            .await?;
1880        let response = self.check_response(response).await?;
1881        let subscription = response.json::<AlertSubscription>().await?;
1882        Ok(subscription)
1883    }
1884
1885    pub async fn update_alert_subscription(
1886        &self,
1887        subscription_id: &str,
1888        request: &UpdateAlertSubscriptionRequest,
1889    ) -> Result<AlertSubscription, LemonaidError> {
1890        let url = format!(
1891            "{}my/alert-subscriptions/{}",
1892            self.base_url, subscription_id
1893        );
1894        let response = self
1895            .client
1896            .put(&url)
1897            .header("Authorization", format!("Bearer {}", self.api_key))
1898            .json(request)
1899            .send()
1900            .await?;
1901        let response = self.check_response(response).await?;
1902        let subscription = response.json::<AlertSubscription>().await?;
1903        Ok(subscription)
1904    }
1905
1906    pub async fn delete_alert_subscription(
1907        &self,
1908        subscription_id: &str,
1909    ) -> Result<(), LemonaidError> {
1910        let url = format!(
1911            "{}my/alert-subscriptions/{}",
1912            self.base_url, subscription_id
1913        );
1914        let response = self
1915            .client
1916            .delete(&url)
1917            .header("Authorization", format!("Bearer {}", self.api_key))
1918            .send()
1919            .await?;
1920        self.check_response(response).await?;
1921        Ok(())
1922    }
1923
1924    // ==================== AUTH ENDPOINTS ====================
1925
1926    pub async fn list_personal_access_tokens(
1927        &self,
1928    ) -> Result<Vec<PersonalAccessToken>, LemonaidError> {
1929        let url = format!("{}auth/personal-access-tokens", self.base_url);
1930        let response = self
1931            .client
1932            .get(&url)
1933            .header("Authorization", format!("Bearer {}", self.api_key))
1934            .send()
1935            .await?;
1936        let response = self.check_response(response).await?;
1937        let wrapper = response.json::<PersonalAccessTokenListResponse>().await?;
1938        Ok(wrapper.tokens)
1939    }
1940
1941    pub async fn delete_personal_access_token(&self, token_id: &str) -> Result<(), LemonaidError> {
1942        let url = format!("{}auth/personal-access-tokens/{}", self.base_url, token_id);
1943        let response = self
1944            .client
1945            .delete(&url)
1946            .header("Authorization", format!("Bearer {}", self.api_key))
1947            .send()
1948            .await?;
1949        self.check_response(response).await?;
1950        Ok(())
1951    }
1952
1953    // ==================== ORBIT DETERMINATION ENDPOINTS ====================
1954
1955    pub async fn solve_orbit_determination(
1956        &self,
1957        request: &ODRequest,
1958    ) -> Result<ODResult, LemonaidError> {
1959        let url = format!("{}od/", self.base_url);
1960        let response = self
1961            .client
1962            .post(&url)
1963            .header("Authorization", format!("Bearer {}", self.api_key))
1964            .json(request)
1965            .send()
1966            .await?;
1967        let response = self.check_response(response).await?;
1968        let result = response.json::<ODResult>().await?;
1969        Ok(result)
1970    }
1971}