using Application.Abstractions.Interfaces; using Application.DTOs.RobotDTOs; using Microsoft.Extensions.Logging; using System.Net.Http; using System.Text; using System.Text.Json; namespace Application.Services { /// /// Service for HTTP communication with Arduino-based drones /// Arduino should have a web server listening on specified port /// public class DroneConnectionService : IDroneConnectionService { private readonly HttpClient _httpClient; private readonly ILogger _logger; public DroneConnectionService(IHttpClientFactory httpClientFactory, ILogger logger) { _httpClient = httpClientFactory.CreateClient("DroneClient"); _httpClient.Timeout = TimeSpan.FromSeconds(10); // Arduino response timeout _logger = logger; } public async Task SendDeliveryCommandAsync(string ipAddress, int port, DroneCommandDTO command) { try { var url = $"http://{ipAddress}:{port}/api/delivery"; var jsonContent = JsonSerializer.Serialize(command, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); _logger.LogInformation($"Sending delivery command to drone at {ipAddress}:{port}"); var response = await _httpClient.PostAsync(url, content); if (response.IsSuccessStatusCode) { var responseJson = await response.Content.ReadAsStringAsync(); var droneResponse = JsonSerializer.Deserialize(responseJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); _logger.LogInformation($"Drone responded: {droneResponse?.Message}"); return droneResponse ?? new DroneResponseDTO { Success = true, Message = "Command sent successfully", OrderId = command.OrderId }; } else { _logger.LogWarning($"Drone returned error: {response.StatusCode}"); return new DroneResponseDTO { Success = false, Message = $"HTTP {response.StatusCode}: {response.ReasonPhrase}", OrderId = command.OrderId }; } } catch (HttpRequestException ex) { _logger.LogError(ex, $"Failed to connect to drone at {ipAddress}:{port}"); return new DroneResponseDTO { Success = false, Message = $"Connection failed: {ex.Message}", OrderId = command.OrderId }; } catch (TaskCanceledException ex) { _logger.LogError(ex, $"Request to drone timed out: {ipAddress}:{port}"); return new DroneResponseDTO { Success = false, Message = "Request timeout - drone not responding", OrderId = command.OrderId }; } catch (Exception ex) { _logger.LogError(ex, $"Unexpected error communicating with drone: {ipAddress}:{port}"); return new DroneResponseDTO { Success = false, Message = $"Error: {ex.Message}", OrderId = command.OrderId }; } } public async Task PingDroneAsync(string ipAddress, int port) { try { var url = $"http://{ipAddress}:{port}/api/ping"; var response = await _httpClient.GetAsync(url); return response.IsSuccessStatusCode; } catch { return false; } } public async Task GetDroneStatusAsync(string ipAddress, int port) { try { var url = $"http://{ipAddress}:{port}/api/status"; var response = await _httpClient.GetAsync(url); if (response.IsSuccessStatusCode) { var responseJson = await response.Content.ReadAsStringAsync(); var droneResponse = JsonSerializer.Deserialize(responseJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); return droneResponse ?? new DroneResponseDTO { Success = true, Message = "Status retrieved" }; } return new DroneResponseDTO { Success = false, Message = $"Failed to get status: {response.StatusCode}" }; } catch (Exception ex) { _logger.LogError(ex, $"Error getting drone status from {ipAddress}:{port}"); return new DroneResponseDTO { Success = false, Message = $"Error: {ex.Message}" }; } } public async Task SendEmergencyStopAsync(string ipAddress, int port) { try { var url = $"http://{ipAddress}:{port}/api/emergency-stop"; var response = await _httpClient.PostAsync(url, null); _logger.LogWarning($"Emergency stop sent to drone at {ipAddress}:{port}"); return response.IsSuccessStatusCode; } catch (Exception ex) { _logger.LogError(ex, $"Failed to send emergency stop to {ipAddress}:{port}"); return false; } } } }