import 'package:excel/excel.dart'; import 'package:intl/intl.dart'; import '../models/panen_model.dart'; import 'excel_save_helper.dart'; class ExcelExportService { static Future exportWeeklyReport({ required List panens, required DateTime startDate, required DateTime endDate, required String kandangFilter, }) async { try { print('[ExcelExportService] Starting export...'); final bytes = _generateExcelContent( panens, startDate, endDate, kandangFilter, ); final now = DateTime.now(); final fileName = 'Laporan_Telur_${_formatDate(now)}.xlsx'; final savedLocation = await saveReportFile( fileName: fileName, bytes: bytes, mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ); print('[ExcelExportService] Export completed successfully'); return savedLocation; } catch (e, stackTrace) { print('[ExcelExportService] ERROR: $e'); print('[ExcelExportService] Stack trace: $stackTrace'); throw Exception('Error creating report: $e'); } } static String _formatDate(DateTime date) { final day = date.day.toString().padLeft(2, '0'); final month = date.month.toString().padLeft(2, '0'); final year = date.year; return '$day-$month-$year'; } static List _generateExcelContent( List panens, DateTime startDate, DateTime endDate, String kandangFilter, ) { final excel = Excel.createExcel(); const sheetName = 'Laporan'; final defaultSheet = excel.getDefaultSheet(); if (defaultSheet != null && defaultSheet != sheetName) { excel.rename(defaultSheet, sheetName); } final sheet = excel[sheetName]; final boldStyle = CellStyle(bold: true); CellIndex idx(int row, int col) => CellIndex.indexByColumnRow(columnIndex: col, rowIndex: row); void writeText(int row, int col, String value, {bool bold = false}) { sheet.updateCell( idx(row, col), TextCellValue(value), cellStyle: bold ? boldStyle : null, ); } void writeInt(int row, int col, int value, {bool bold = false}) { sheet.updateCell( idx(row, col), IntCellValue(value), cellStyle: bold ? boldStyle : null, ); } int totalKandang1Pagi = 0; int totalKandang1Sore = 0; int totalKandang2Pagi = 0; int totalKandang2Sore = 0; int totalOverall = 0; final perHari = {}; for (final panen in panens) { final dateKey = DateTime( panen.tanggalPanen.year, panen.tanggalPanen.month, panen.tanggalPanen.day, ); final daily = perHari.putIfAbsent(dateKey, () => _DailyReport()); final jumlah = panen.jumlahTelur; final normalized = _normalizeKandang(panen.kandangId, panen.kandangNama); final jenis = _normalizeJenisPanen(panen); if (normalized.contains('kandang1')) { if (jenis == 'pagi') { totalKandang1Pagi += jumlah; daily.kandang1Pagi += jumlah; } else if (jenis == 'sore') { totalKandang1Sore += jumlah; daily.kandang1Sore += jumlah; } } else if (normalized.contains('kandang2')) { if (jenis == 'pagi') { totalKandang2Pagi += jumlah; daily.kandang2Pagi += jumlah; } else if (jenis == 'sore') { totalKandang2Sore += jumlah; daily.kandang2Sore += jumlah; } } totalOverall += jumlah; daily.total += jumlah; } final periodText = '${DateFormat('dd/MM/yyyy').format(startDate)} - ${DateFormat('dd/MM/yyyy').format(endDate)}'; final filterText = kandangFilter == 'semua' ? 'Semua Kandang' : kandangFilter; writeText(0, 0, 'LAPORAN PRODUKSI TELUR', bold: true); writeText(1, 0, 'Periode', bold: true); writeText(1, 1, periodText); writeText(2, 0, 'Filter Kandang', bold: true); writeText(2, 1, filterText); final totalKandang1 = totalKandang1Pagi + totalKandang1Sore; final totalKandang2 = totalKandang2Pagi + totalKandang2Sore; writeText(4, 0, 'Jumlah total telur kandang 1 (pagi)', bold: true); writeInt(4, 1, totalKandang1Pagi, bold: true); writeText(5, 0, 'Jumlah total telur kandang 1 (sore)', bold: true); writeInt(5, 1, totalKandang1Sore, bold: true); writeText(6, 0, 'Jumlah total telur kandang 1', bold: true); writeInt(6, 1, totalKandang1, bold: true); writeText(8, 0, 'Jumlah total telur kandang 2 (pagi)', bold: true); writeInt(8, 1, totalKandang2Pagi, bold: true); writeText(9, 0, 'Jumlah total telur kandang 2 (sore)', bold: true); writeInt(9, 1, totalKandang2Sore, bold: true); writeText(10, 0, 'Jumlah total telur kandang 2', bold: true); writeInt(10, 1, totalKandang2, bold: true); writeText(12, 0, 'Total keseluruhan', bold: true); writeInt(12, 1, totalOverall, bold: true); writeText(14, 0, 'Tanggal', bold: true); writeText(14, 1, 'Kandang 1 Pagi', bold: true); writeText(14, 2, 'Kandang 1 Sore', bold: true); writeText(14, 3, 'Kandang 2 Pagi', bold: true); writeText(14, 4, 'Kandang 2 Sore', bold: true); writeText(14, 5, 'Total Telur Per Hari', bold: true); final sortedDates = perHari.keys.toList()..sort((a, b) => a.compareTo(b)); var row = 15; for (final date in sortedDates) { final daily = perHari[date]!; writeText(row, 0, DateFormat('dd/MM/yyyy').format(date)); writeInt(row, 1, daily.kandang1Pagi); writeInt(row, 2, daily.kandang1Sore); writeInt(row, 3, daily.kandang2Pagi); writeInt(row, 4, daily.kandang2Sore); writeInt(row, 5, daily.total); row++; } final encoded = excel.encode(); if (encoded == null) { throw Exception('Gagal membuat file Excel'); } return encoded; } static String _normalizeKandang(String kandangId, String kandangNama) { return '${kandangId.toLowerCase()} ${kandangNama.toLowerCase()}' .replaceAll('_', '') .replaceAll(' ', ''); } static String _normalizeJenisPanen(Panen panen) { final explicit = (panen.jenisPanen ?? '').trim().toLowerCase(); if (explicit == 'pagi' || explicit == 'sore') { return explicit; } final match = RegExp(r'^(\d{1,2})[:.]').firstMatch(panen.jam.trim()); final hour = match != null ? int.tryParse(match.group(1)!) : null; if (hour != null) { return hour < 12 ? 'pagi' : 'sore'; } return 'sore'; } } class _DailyReport { int kandang1Pagi = 0; int kandang1Sore = 0; int kandang2Pagi = 0; int kandang2Sore = 0; int total = 0; }