using LSFE.Infrastructure.Model.Admin; using LSFE.MobApp.Contracts; using LSFE.MobApp.Models; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace LSFE.MobApp.Services { public class ApiClient : IApiClient where T : class { private readonly HttpClient _httpClient; private readonly string _baseEndpoint; private readonly JsonSerializerOptions _jsonOptions; public ApiClient(HttpClient httpClient, string baseEndpoint) { _httpClient = httpClient; _baseEndpoint = baseEndpoint; _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, WriteIndented = false }; } public async Task> GetAllAsync() { try { var response = await _httpClient.GetAsync(_baseEndpoint); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize>(json, _jsonOptions) ?? new List(); } catch (Exception ex) { Debug.WriteLine($"Error in GetAllAsync: {ex.Message}"); return new List(); } } public async Task> GetWithQueryAsync(Dictionary queryParams) { try { var query = string.Join("&", queryParams .Where(kv => !string.IsNullOrEmpty(kv.Value)) .Select(kv => $"{kv.Key}={Uri.EscapeDataString(kv.Value)}")); var url = string.IsNullOrEmpty(query) ? _baseEndpoint : $"{_baseEndpoint}?{query}"; var response = await _httpClient.GetAsync(url); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize>(json, _jsonOptions); } catch (Exception ex) { Debug.WriteLine($"Error in GetWithQueryAsync: {ex.Message}"); return null; } } public async Task LoginAsync(LoginRequest entity) { try { var json = JsonSerializer.Serialize(entity, _jsonOptions); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync(_baseEndpoint, content); var responseJson = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize(responseJson, _jsonOptions); } catch (Exception ex) { Debug.WriteLine($"Error in LoginAsync: {ex.Message}"); return null; } } public async Task GetByIdAsync(int id) { try { var response = await _httpClient.GetAsync($"{_baseEndpoint}/{id}"); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize(json, _jsonOptions); } catch (Exception ex) { Debug.WriteLine($"Error in GetByIdAsync: {ex.Message}"); return null; } } public async Task> CreateAsync(T entity) { try { var json = JsonSerializer.Serialize(entity, _jsonOptions); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync(_baseEndpoint, content); var responseJson = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize>(responseJson, _jsonOptions); } catch (Exception ex) { return new ApiResponse { Success = false, Message = ex.Message, MessCode = 0 }; } } public async Task> CreateAttendanceAsync(T entity) { try { using var form = new MultipartFormDataContent(); // Convert your entity (Attendance) into key-value form fields foreach (var prop in typeof(T).GetProperties()) { var value = prop.GetValue(entity); if (value != null) { // Skip SignatureImage byte array - we'll send the files instead if (prop.Name == "SignatureImage") continue; // Convert Guid to string for AppAttendanceId if (prop.Name == "AppAttendanceId" && value is Guid guid) { form.Add(new StringContent(guid.ToString()), prop.Name); } // Handle DateTime properties with ISO format else if (value is DateTime dateTime) { form.Add(new StringContent(dateTime.ToString("o")), prop.Name); // ISO 8601 format } else { form.Add(new StringContent(value.ToString()), prop.Name); } } } // Add Time-In photo if exists var fileInProp = typeof(T).GetProperty("SignatureFileNameIn"); if (fileInProp != null) { var fileName = fileInProp.GetValue(entity)?.ToString(); if (!string.IsNullOrEmpty(fileName)) { var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName); if (File.Exists(filePath)) { var stream = File.OpenRead(filePath); var fileContent = new StreamContent(stream); fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg"); form.Add(fileContent, "photoFileIn", fileName); } else { Debug.WriteLine($"Time-In file not found: {filePath}"); } } } // Add Time-Out photo if exists var fileOutProp = typeof(T).GetProperty("SignatureFileNameOut"); if (fileOutProp != null) { var fileName = fileOutProp.GetValue(entity)?.ToString(); if (!string.IsNullOrEmpty(fileName)) { var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName); if (File.Exists(filePath)) { var stream = File.OpenRead(filePath); var fileContent = new StreamContent(stream); fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg"); form.Add(fileContent, "photoFileOut", fileName); } else { Debug.WriteLine($"Time-Out file not found: {filePath}"); } } } var response = await _httpClient.PostAsync(_baseEndpoint, form); var responseJson = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { return new ApiResponse { Success = false, Message = $"API returned {response.StatusCode}: {responseJson}", MessCode = 0 }; } return JsonSerializer.Deserialize>(responseJson, _jsonOptions); } catch (Exception ex) { Debug.WriteLine($"CreateWithPhotoAsync Exception: {ex.ToString()}"); return new ApiResponse { Success = false, Message = ex.Message, MessCode = 0 }; } } public async Task> CreateCoveragePlanAsync(T entity) { try { using var form = new MultipartFormDataContent(); // Convert your entity (MRRawPlan) into key-value form fields foreach (var prop in typeof(T).GetProperties()) { var value = prop.GetValue(entity); if (value != null) { // Skip SignatureBase64 if it exists - we'll send the file instead if (prop.Name == "SignatureBase64") continue; // Convert Guid to string if (value is Guid guid) { form.Add(new StringContent(guid.ToString()), prop.Name); } // Handle DateTime properties with ISO format else if (value is DateTime dateTime) { form.Add(new StringContent(dateTime.ToString("o")), prop.Name); // ISO 8601 format } // Handle boolean else if (value is bool boolValue) { form.Add(new StringContent(boolValue.ToString().ToLower()), prop.Name); } else { form.Add(new StringContent(value.ToString()), prop.Name); } } } // Add Signature photo if exists var fileNameProp = typeof(T).GetProperty("SignatureFileName"); if (fileNameProp != null) { var fileName = fileNameProp.GetValue(entity)?.ToString(); if (!string.IsNullOrEmpty(fileName)) { var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName); if (File.Exists(filePath)) { var stream = File.OpenRead(filePath); var fileContent = new StreamContent(stream); fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png"); form.Add(fileContent, "photoFile", fileName); } else { Debug.WriteLine($"Signature file not found: {filePath}"); return new ApiResponse { Success = false, Message = $"Signature file not found at: {filePath}", MessCode = 0 }; } } else { Debug.WriteLine("SignatureFileName is null or empty"); } } var response = await _httpClient.PostAsync(_baseEndpoint, form); var responseJson = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { Debug.WriteLine($"API Error: {response.StatusCode} - {responseJson}"); return new ApiResponse { Success = false, Message = $"API returned {response.StatusCode}: {responseJson}", MessCode = 0 }; } return JsonSerializer.Deserialize>(responseJson, _jsonOptions); } catch (Exception ex) { Debug.WriteLine($"CreateWithPhotoAsync Exception: {ex.ToString()}"); return new ApiResponse { Success = false, Message = ex.Message, MessCode = 0 }; } } public async Task GetByIdAsync(Guid id) { try { var response = await _httpClient.GetAsync($"{_baseEndpoint}/{id}"); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); Debug.WriteLine($"GetByIdAsync Response: {json}"); return JsonSerializer.Deserialize(json, _jsonOptions); } catch (Exception ex) { Debug.WriteLine($"Error in GetByIdAsync: {ex.Message}"); return null; } } public async Task> UpdateAsync(Guid id, T entity) { try { var json = JsonSerializer.Serialize(entity, _jsonOptions); Debug.WriteLine($"UpdateAsync Request: {json}"); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _httpClient.PutAsync($"{_baseEndpoint}/{id}", content); var responseJson = await response.Content.ReadAsStringAsync(); Debug.WriteLine($"UpdateAsync Response: {responseJson}"); if (!response.IsSuccessStatusCode) { return new ApiResponse { Success = false, Message = $"Server returned {response.StatusCode}: {responseJson}", MessCode = (int)response.StatusCode }; } return JsonSerializer.Deserialize>(responseJson, _jsonOptions); } catch (Exception ex) { Debug.WriteLine($"Error in UpdateAsync: {ex.Message}"); return new ApiResponse { Success = false, Message = ex.Message, MessCode = 0 }; } } public async Task> DeleteAsync(Guid id) { try { var response = await _httpClient.DeleteAsync($"{_baseEndpoint}/{id}"); var responseJson = await response.Content.ReadAsStringAsync(); Debug.WriteLine($"DeleteAsync Response: {responseJson}"); if (!response.IsSuccessStatusCode) { return new ApiResponse { Success = false, Message = $"Server returned {response.StatusCode}: {responseJson}", MessCode = (int)response.StatusCode }; } return JsonSerializer.Deserialize>(responseJson, _jsonOptions) ?? new ApiResponse { Success = true, Message = "Deleted successfully", MessCode = 200 }; } catch (Exception ex) { Debug.WriteLine($"Error in DeleteAsync: {ex.Message}"); return new ApiResponse { Success = false, Message = ex.Message, MessCode = 0 }; } } } }