using System.Text.Json; using eSPJ.Models; namespace eSPJ.Services { public class DetailPenjemputanService { private readonly string _dataFilePath; private readonly IWebHostEnvironment _env; private readonly ILogger _logger; public DetailPenjemputanService( IWebHostEnvironment env, ILogger logger) { _env = env; _logger = logger; _dataFilePath = Path.Combine(_env.ContentRootPath, "Data", "detail-penjemputan.json"); } public async Task> GetAllTpsDataAsync() { try { if (!File.Exists(_dataFilePath)) { return new List(); } var json = await File.ReadAllTextAsync(_dataFilePath); var data = JsonSerializer.Deserialize>(json); return data ?? new List(); } catch (Exception ex) { _logger.LogError(ex, "Error reading TPS data from JSON"); return new List(); } } public async Task SaveTpsDataAsync(List data) { try { var directory = Path.GetDirectoryName(_dataFilePath); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } var options = new JsonSerializerOptions { WriteIndented = true }; var json = JsonSerializer.Serialize(data, options); await File.WriteAllTextAsync(_dataFilePath, json); return true; } catch (Exception ex) { _logger.LogError(ex, "Error saving TPS data to JSON"); return false; } } public async Task SubmitPenjemputanAsync(DetailPenjemputanRequest request) { try { // Validate request if (string.IsNullOrEmpty(request.TpsName)) { return new DetailPenjemputanResponse { Success = false, Message = "Nama TPS harus diisi" }; } if (request.FotoKedatangan == null || !request.FotoKedatangan.Any()) { return new DetailPenjemputanResponse { Success = false, Message = "Foto kedatangan harus diupload" }; } if (request.FotoTimbangan == null || !request.FotoTimbangan.Any()) { return new DetailPenjemputanResponse { Success = false, Message = "Foto timbangan harus diupload" }; } if (request.FotoPetugas == null || !request.FotoPetugas.Any()) { return new DetailPenjemputanResponse { Success = false, Message = "Foto petugas harus diupload" }; } if (string.IsNullOrEmpty(request.NamaPetugas)) { return new DetailPenjemputanResponse { Success = false, Message = "Nama petugas harus diisi" }; } var uploadPath = Path.Combine(_env.ContentRootPath, "uploads", "penjemputan", DateTime.Now.ToString("yyyy-MM-dd")); if (!Directory.Exists(uploadPath)) { Directory.CreateDirectory(uploadPath); } var tpsData = new TpsData { Name = request.TpsName, Latitude = request.Latitude, Longitude = request.Longitude, AlamatJalan = request.AlamatJalan, WaktuKedatangan = request.WaktuKedatangan, TotalTimbangan = request.TotalTimbangan, TotalOrganik = request.TotalOrganik, TotalAnorganik = request.TotalAnorganik, TotalResidu = request.TotalResidu, NamaPetugas = request.NamaPetugas, Submitted = true, FotoKedatanganUploaded = true, FotoPetugasUploaded = true }; // Save foto kedatangan foreach (var file in request.FotoKedatangan) { var fileName = $"kedatangan_{Guid.NewGuid()}{Path.GetExtension(file.FileName)}"; var filePath = Path.Combine(uploadPath, fileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } tpsData.FotoKedatangan.Add($"{uploadBaseUrl}/{fileName}"); } // Save foto timbangan if (request.BeratTimbangan != null && request.JenisSampahList != null) { for (int i = 0; i < request.FotoTimbangan.Count; i++) { var file = request.FotoTimbangan[i]; var fileName = $"timbangan_{Guid.NewGuid()}{Path.GetExtension(file.FileName)}"; var filePath = Path.Combine(uploadPath, fileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } var jenisSampah = JenisSampah.Residu; if (i < request.JenisSampahList.Count && Enum.TryParse(request.JenisSampahList[i], out var parsed)) { jenisSampah = parsed; } tpsData.Timbangan.Add(new TimbanganItem { FotoFileName = $"{uploadBaseUrl}/{fileName}", Berat = new List { (i < request.BeratTimbangan.Count ? request.BeratTimbangan[i] : 0) }, LokasiAngkut = new List(), JenisSampah = new List { jenisSampah }, IsUploaded = true, WaktuUpload = DateTime.Now }); } } // Save foto petugas foreach (var file in request.FotoPetugas) { var fileName = $"petugas_{Guid.NewGuid()}{Path.GetExtension(file.FileName)}"; var filePath = Path.Combine(uploadPath, fileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } tpsData.FotoPetugas.Add($"{uploadBaseUrl}/{fileName}"); } var allData = await GetAllTpsDataAsync(); allData.Add(tpsData); await SaveTpsDataAsync(allData); return new DetailPenjemputanResponse { Success = true, Message = "Data penjemputan berhasil disimpan", Data = tpsData }; } catch (Exception ex) { _logger.LogError(ex, "Error submitting penjemputan data"); return new DetailPenjemputanResponse { Success = false, Message = $"Terjadi kesalahan: {ex.Message}" }; } } private string GetDraftFilePath(string prefix, string sessionKey) { var dir = Path.Combine(_env.ContentRootPath, "Data", "drafts"); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); var safe = string.Concat(sessionKey.Where(c => char.IsLetterOrDigit(c) || c == '-' || c == '_')); if (string.IsNullOrEmpty(safe)) safe = "default"; return Path.Combine(dir, $"draft-{prefix}-{safe}.json"); } private Task SaveDraftAsync(string prefix, DraftSaveRequest request) { return SaveDraftInternalAsync(prefix, request); } private async Task SaveDraftInternalAsync(string prefix, DraftSaveRequest request) { try { var filePath = GetDraftFilePath(prefix, request.SessionKey); var draft = new DraftPenjemputanNonTps { SessionKey = request.SessionKey, LokasiAngkutId = request.LokasiAngkutId, SpjDetailId = request.SpjDetailId, Latitude = request.Latitude, Longitude = request.Longitude, AlamatJalan = request.AlamatJalan, WaktuKedatangan = request.WaktuKedatangan, FotoKedatanganFileNames = request.FotoKedatanganFileNames, FotoKedatanganUploaded = request.FotoKedatanganUploaded, Timbangan = request.Timbangan, TotalOrganik = request.TotalOrganik, TotalAnorganik = request.TotalAnorganik, TotalResidu = request.TotalResidu, TotalTimbangan = request.TotalTimbangan, FotoPetugasFileNames = request.FotoPetugasFileNames, FotoPetugasUploaded = request.FotoPetugasUploaded, NamaPetugas = request.NamaPetugas, UpdatedAt = DateTime.Now }; var options = new JsonSerializerOptions { WriteIndented = true }; var json = JsonSerializer.Serialize(draft, options); await File.WriteAllTextAsync(filePath, json); return new DraftSaveResponse { Success = true, Message = "Draft tersimpan.", DraftKey = request.DraftKey, SessionKey = request.SessionKey }; } catch (Exception ex) { _logger.LogError(ex, "Error saving {Prefix} draft", prefix); return new DraftSaveResponse { Success = false, Message = $"Gagal menyimpan draft: {ex.Message}" }; } } public async Task SaveDraftNonTpsAsync(DraftSaveRequest request) { return await SaveDraftAsync("non-tps", request); } public async Task SaveDraftTpsAsync(DraftSaveRequest request) { return await SaveDraftAsync("tps", request); } public async Task LoadDraftNonTpsAsync(string sessionKey) { return await LoadDraftAsync("non-tps", sessionKey); } public async Task LoadDraftTpsAsync(string sessionKey) { return await LoadDraftAsync("tps", sessionKey); } private async Task LoadDraftAsync(string prefix, string sessionKey) { try { var filePath = GetDraftFilePath(prefix, sessionKey); if (!File.Exists(filePath)) return new DraftLoadResponse { Success = true, HasDraft = false, Message = "Tidak ada draft." }; var json = await File.ReadAllTextAsync(filePath); var draft = JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); if (draft == null) return new DraftLoadResponse { Success = true, HasDraft = false, Message = "Draft kosong." }; return new DraftLoadResponse { Success = true, HasDraft = true, Draft = draft }; } catch (Exception ex) { _logger.LogError(ex, "Error loading {Prefix} draft", prefix); return new DraftLoadResponse { Success = false, HasDraft = false, Message = $"Gagal memuat draft: {ex.Message}" }; } } public async Task DeleteDraftNonTpsAsync(string sessionKey) { return await DeleteDraftAsync("non-tps", sessionKey); } public async Task DeleteDraftTpsAsync(string sessionKey) { return await DeleteDraftAsync("tps", sessionKey); } private async Task DeleteDraftAsync(string prefix, string sessionKey) { try { var filePath = GetDraftFilePath(prefix, sessionKey); if (File.Exists(filePath)) File.Delete(filePath); await Task.CompletedTask; return true; } catch (Exception ex) { _logger.LogError(ex, "Error deleting {Prefix} draft", prefix); return false; } } public async Task ProcessOcrTimbanganAsync(IFormFile foto) { try { await Task.Delay(500); return new OcrTimbanganResponse { Success = true, Weight = "54.50", Raw = "54.50 kg", Message = "OCR processed successfully (mock)" }; } catch (Exception ex) { _logger.LogError(ex, "Error processing OCR timbangan"); return new OcrTimbanganResponse { Success = false, Message = $"Terjadi kesalahan: {ex.Message}" }; } } } }