using Microsoft.EntityFrameworkCore; using System.Linq; using eprintServer.Data; using eprintServer.Entities; using eprintServer.Enums; using eprintServer.Requests; using System.Net.Http.Headers; using System.Text.Json; using System.Text; namespace eprintServer.Services; public class AsyadExpressService { private readonly HttpClient _http; private readonly DataContext _context; private const string BaseUrl = "https://apix.stag.asyadexpress.com"; public AsyadExpressService(HttpClient http, DataContext context) { _http = http; _context = context; } public async Task LoginAsync(string username, string password) { var loginPayload = new { username = username, password = password }; var response = await _http.PostAsJsonAsync($"{BaseUrl}/login", loginPayload); return await response.Content.ReadAsStringAsync(); } public async Task ProcessAsyadShipmentAsync(CreateAsyadShipmentRequest req, string asyadLoginToken, string? batchId = null) { // 1. Fetch Order with User, Address, and localized Names var order = await _context.Orders .Include(o => o.User) .Include(o => o.UserAddress) .Include(o => o.OrderItems).ThenInclude(oi => oi.SellableProduct).ThenInclude(p => p.Names) .Include(o => o.OrderItems).ThenInclude(oi => oi.CustomizableProduct).ThenInclude(p => p.Names) .FirstOrDefaultAsync(o => o.Id == req.OrderId); if (order == null || order.UserAddress == null) throw new Exception("Order or Shipping Address not found."); // 2. Reference & Batch Logic var referenceCount = await _context.Orders.CountAsync(o => o.BatchId != null); string shippingRef = $"PRINT_SHIPP_{referenceCount + 1}"; order.ShippingRef = shippingRef; order.BatchId = batchId ?? $"BATCH_{DateTime.UtcNow:yyyyMMdd_HHmm}"; // 3. Prepare Package and Performa Data var packageDetails = new List(); var performaInvoice = new List(); foreach (var pkgInput in req.Packages) { var item = order.OrderItems.FirstOrDefault(oi => oi.Id == pkgInput.OrderItemId); if (item == null) continue; string generatedAwb = $"PKG-{Guid.NewGuid().ToString().Substring(0, 8).ToUpper()}"; item.PackageAwb = generatedAwb; var names = item.SellableProduct?.Names ?? item.CustomizableProduct?.Names; string resolvedName = names?.FirstOrDefault(n => n.LanguageTag == "en")?.Value ?? names?.FirstOrDefault(n => n.LanguageTag == "ar")?.Value ?? "Printed Product"; packageDetails.Add(new { Package_AWB = generatedAwb, Weight = pkgInput.Weight, Width = pkgInput.Width, Length = pkgInput.Length, Height = pkgInput.Height }); performaInvoice.Add(new { HSCode = "4901", ProductDescription = resolvedName, ItemQuantity = item.Quantity, ProductDeclaredValue = item.UnitPrice, itemRef = $"ITM-{item.Id}", ShipmentTypeCode = "Product", PackageTypeCode = "BOX" }); } if (!packageDetails.Any()) throw new Exception("PackageDetails is required."); // 4. Build Final Payload var payload = new { ClientOrderRef = shippingRef, Description = $"Order No: {order.Id}", HandlingType = "Others", ShippingCost = 0, PaymentType = "COD", CODAmount = order.TotalAmount, ShipmentProduct = "EXPRESS", ShipmentService = "ALL_DAY", OrderType = "PICKUP", PickupType = "NEXTDAY", PickupDate = DateTime.UtcNow.AddDays(1).ToString("yyyy-MM-dd"), TotalShipmentValue = order.TotalAmount, JourneyOptions = new { NOReturn = true, Extra = new { } }, Consignee = new { Name = !string.IsNullOrWhiteSpace(order.User.Name) ? order.User.Name : "Customer", MobileNo = FormatAsyadPhone(order.User.PhoneNumber), PhoneNo = "", Email = !string.IsNullOrWhiteSpace(order.User.Email) ? order.User.Email : "customer@eprint.om", AddressLine1 = !string.IsNullOrWhiteSpace(order.UserAddress.AddressLine1) ? order.UserAddress.AddressLine1 : "Oman Address", // If the Area/Zip is failing, we fallback to the Muscat center defaults Area = !string.IsNullOrWhiteSpace(order.UserAddress.Area) ? order.UserAddress.Area : "Muscat", City = !string.IsNullOrWhiteSpace(order.UserAddress.City) ? order.UserAddress.City : "Muscat", Region = !string.IsNullOrWhiteSpace(order.UserAddress.Region) ? order.UserAddress.Region : "Muscat", Country = "Oman", ZipCode = !string.IsNullOrWhiteSpace(order.UserAddress.ZipCode) ? order.UserAddress.ZipCode : "100", Latitude = "23.588", Longitude = "58.284", Instruction = "" }, Shipper = new { ReturnAsSame = true, ContactName = req.ShipperContactName, CompanyName = req.ShipperCompanyName, AddressLine1 = req.ShipperAddress, Area = !string.IsNullOrWhiteSpace(req.ShipperCity) ? req.ShipperCity : "Muscat", City = !string.IsNullOrWhiteSpace(req.ShipperCity) ? req.ShipperCity : "Muscat", Region = "Muscat", Country = "Oman", MobileNo = FormatAsyadPhone(req.ShipperMobile), Email = req.ShipperEmail, ZipCode = !string.IsNullOrWhiteSpace(req.ZipCode) ? req.ZipCode : "100", Latitude = "23.581", Longitude = "58.257" }, PackageDetails = packageDetails, ShipmentPerformaInvoice = performaInvoice }; // 5. Send to Asyad var requestMessage = new HttpRequestMessage(HttpMethod.Post, $"{BaseUrl}/v2/orders"); requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", asyadLoginToken); // CRITICAL: Force the serializer to keep "ZipCode" as you typed it (no camelCase) string jsonPayload = System.Text.Json.JsonSerializer.Serialize(payload, new System.Text.Json.JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true // Useful for debugging }); requestMessage.Content = new StringContent(jsonPayload, System.Text.Encoding.UTF8, "application/json"); var response = await _http.SendAsync(requestMessage); var resultString = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { using var doc = System.Text.Json.JsonDocument.Parse(resultString); if (doc.RootElement.TryGetProperty("data", out var dataElement) && dataElement.TryGetProperty("order_awb_number", out var awbProp)) { order.TrackingNumber = awbProp.GetString(); } order.Status = OrderStatus.SHIPPED; await _context.SaveChangesAsync(); } return resultString; } public async Task GetAsyadProfileAsync(string token) { var requestMessage = new HttpRequestMessage(HttpMethod.Get, $"{BaseUrl}/me"); requestMessage.Headers.Add("accept", "application/json"); requestMessage.Headers.Add("Authorization", token); var response = await _http.SendAsync(requestMessage); // Return the raw JSON string to the controller return await response.Content.ReadAsStringAsync(); } private string FormatAsyadPhone(string? phone) { if (string.IsNullOrWhiteSpace(phone)) return "+96890000000"; // 1. Remove everything that isn't a digit var digitsOnly = new string(phone.Where(char.IsDigit).ToArray()); // 2. If it starts with 00968, swap to +968 if (digitsOnly.StartsWith("00968")) return "+968" + digitsOnly.Substring(5); // 3. If it starts with 968 but no +, add it if (digitsOnly.StartsWith("968")) return "+968" + digitsOnly.Substring(3); // 4. If it's just the 8-digit local number (e.g. 92252712) if (digitsOnly.Length == 8) return "+968" + digitsOnly; // 5. If it's already got the + but digitsOnly stripped it return "+968" + digitsOnly.TakeLast(8); } /* public async Task CreateOrderTestAsync() { // Using your provided direct token string token = "1Y97Yh1WHuSX-7-YsaDbepD9aYDL9Cqs"; var rawPayload = $@" {{ ""ClientOrderRef"": ""PRINT_TEST_{Guid.NewGuid().ToString().Substring(0, 8)}"", ""Description"": ""PRINT Test Order"", ""HandlingType"": ""Others"", ""ShippingCost"": 0, ""PaymentType"": ""COD"", ""CODAmount"": 10, ""ShipmentProduct"": ""EXPRESS"", ""ShipmentService"": ""ALL_DAY"", ""OrderType"": ""DROPOFF"", ""PickupType"": """", ""PickupDate"": """", ""TotalShipmentValue"": ""10"", ""JourneyOptions"": {{ ""NOReturn"": true, ""Extra"": {{}} }}, ""Consignee"": {{ ""Name"": ""PRINT Test Receiver"", ""CompanyName"": ""Test Company"", ""MobileNo"": ""+96892345678"", ""PhoneNo"": """", ""Email"": ""receiver@example.com"", ""AddressLine1"": ""Street 1"", ""AddressLine2"": """", ""Area"": ""Muttrah"", ""City"": ""Muttrah"", ""Region"": ""Muscat"", ""Country"": ""Oman"", ""ZipCode"": ""125"", ""Latitude"": ""23.588"", ""Longitude"": ""58.284"", ""Instruction"": ""Handle with care"", ""What3Words"": """", ""NationalId"": """", ""ReferenceNo"": """", ""Vattaxcode"": """", ""Eorinumber"": """" }}, ""Shipper"": {{ ""ReturnAsSame"": true, ""ContactName"": ""PRINT Test Sender"", ""CompanyName"": ""Senders Co"", ""AddressLine1"": ""Warehouse A"", ""AddressLine2"": """", ""Area"": ""Al Seeb"", ""City"": ""Al Seeb"", ""Region"": ""Muscat"", ""Country"": ""Oman"", ""ZipCode"": ""121"", ""MobileNo"": ""+96872345678"", ""TelephoneNo"": """", ""Email"": ""sender@example.com"", ""Latitude"": ""23.581"", ""Longitude"": ""58.257"", ""NationalId"": """", ""What3Words"": """", ""ReferenceOrderNo"": """", ""Vattaxcode"": """", ""Eorinumber"": """" }}, ""PackageDetails"": [ {{ ""Package_AWB"": ""PKG-{Guid.NewGuid().ToString().Substring(0, 5)}"", ""Weight"": 1, ""Width"": 10, ""Length"": 10, ""Height"": 10 }} ], ""ShipmentPerformaInvoice"": [ {{ ""HSCode"": ""1234"", ""ProductDescription"": ""Test Product"", ""ItemQuantity"": 1, ""ProductDeclaredValue"": 10, ""itemRef"": ""ITM-001"", ""ShipmentTypeCode"": ""Document"", ""PackageTypeCode"": ""POUCH"" }} ] }}"; var request = new HttpRequestMessage(HttpMethod.Post, $"{BaseUrl}/v2/orders"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); request.Content = new StringContent(rawPayload, Encoding.UTF8, "application/json"); var response = await _http.SendAsync(request); return await response.Content.ReadAsStringAsync(); } */ }