package services import ( "bytes" "fmt" "time" "github.com/jung-kurt/gofpdf" ) // PDFService handles PDF generation type PDFService struct{} // NewPDFService creates a new PDF service func NewPDFService() *PDFService { return &PDFService{} } // GenerateTasksReportPDF generates a PDF report from task report data func (s *PDFService) GenerateTasksReportPDF(report *TasksReportResponse) ([]byte, error) { pdf := gofpdf.New("P", "mm", "A4", "") pdf.SetMargins(15, 15, 15) pdf.AddPage() // Header pdf.SetFont("Arial", "B", 20) pdf.SetTextColor(51, 51, 51) pdf.Cell(0, 12, "Tasks Report") pdf.Ln(14) // Residence name pdf.SetFont("Arial", "", 14) pdf.SetTextColor(102, 102, 102) pdf.Cell(0, 8, report.ResidenceName) pdf.Ln(10) // Generated date pdf.SetFont("Arial", "", 10) pdf.Cell(0, 6, fmt.Sprintf("Generated: %s", report.GeneratedAt.Format("January 2, 2006 at 3:04 PM"))) pdf.Ln(12) // Summary section pdf.SetFont("Arial", "B", 14) pdf.SetTextColor(51, 51, 51) pdf.Cell(0, 8, "Summary") pdf.Ln(10) // Summary box pdf.SetFillColor(248, 249, 250) pdf.Rect(15, pdf.GetY(), 180, 30, "F") y := pdf.GetY() + 5 pdf.SetXY(20, y) pdf.SetFont("Arial", "B", 12) pdf.SetTextColor(51, 51, 51) // Summary columns colWidth := 45.0 pdf.Cell(colWidth, 6, "Total Tasks") pdf.Cell(colWidth, 6, "Completed") pdf.Cell(colWidth, 6, "Pending") pdf.Cell(colWidth, 6, "Overdue") pdf.Ln(8) pdf.SetX(20) pdf.SetFont("Arial", "", 16) pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.TotalTasks)) pdf.SetTextColor(40, 167, 69) // Green pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.Completed)) pdf.SetTextColor(255, 193, 7) // Yellow/Orange pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.Pending)) pdf.SetTextColor(220, 53, 69) // Red pdf.Cell(colWidth, 8, fmt.Sprintf("%d", report.Overdue)) pdf.Ln(25) // Tasks table pdf.SetTextColor(51, 51, 51) pdf.SetFont("Arial", "B", 14) pdf.Cell(0, 8, "Tasks") pdf.Ln(10) if len(report.Tasks) == 0 { pdf.SetFont("Arial", "I", 11) pdf.SetTextColor(128, 128, 128) pdf.Cell(0, 8, "No tasks found for this residence.") } else { // Table header pdf.SetFont("Arial", "B", 10) pdf.SetFillColor(233, 236, 239) pdf.SetTextColor(51, 51, 51) pdf.CellFormat(70, 8, "Title", "1", 0, "L", true, 0, "") pdf.CellFormat(30, 8, "Category", "1", 0, "C", true, 0, "") pdf.CellFormat(25, 8, "Priority", "1", 0, "C", true, 0, "") pdf.CellFormat(25, 8, "Status", "1", 0, "C", true, 0, "") pdf.CellFormat(30, 8, "Due Date", "1", 0, "C", true, 0, "") pdf.Ln(-1) // Table rows pdf.SetFont("Arial", "", 9) for _, task := range report.Tasks { // Check if we need a new page if pdf.GetY() > 270 { pdf.AddPage() // Repeat header pdf.SetFont("Arial", "B", 10) pdf.SetFillColor(233, 236, 239) pdf.CellFormat(70, 8, "Title", "1", 0, "L", true, 0, "") pdf.CellFormat(30, 8, "Category", "1", 0, "C", true, 0, "") pdf.CellFormat(25, 8, "Priority", "1", 0, "C", true, 0, "") pdf.CellFormat(25, 8, "Status", "1", 0, "C", true, 0, "") pdf.CellFormat(30, 8, "Due Date", "1", 0, "C", true, 0, "") pdf.Ln(-1) pdf.SetFont("Arial", "", 9) } // Determine row color based on status if task.IsCancelled { pdf.SetFillColor(248, 215, 218) // Light red } else if task.IsCompleted { pdf.SetFillColor(212, 237, 218) // Light green } else if task.IsArchived { pdf.SetFillColor(226, 227, 229) // Light gray } else { pdf.SetFillColor(255, 255, 255) // White } // Title (truncate if too long) title := task.Title if len(title) > 35 { title = title[:32] + "..." } // Status text var status string if task.IsCancelled { status = "Cancelled" } else if task.IsCompleted { status = "Completed" } else if task.IsArchived { status = "Archived" } else { status = task.Status } // Due date dueDate := "-" if task.DueDate != nil { dueDate = task.DueDate.Format("Jan 2, 2006") } pdf.SetTextColor(51, 51, 51) pdf.CellFormat(70, 7, title, "1", 0, "L", true, 0, "") pdf.CellFormat(30, 7, task.Category, "1", 0, "C", true, 0, "") pdf.CellFormat(25, 7, task.Priority, "1", 0, "C", true, 0, "") pdf.CellFormat(25, 7, status, "1", 0, "C", true, 0, "") pdf.CellFormat(30, 7, dueDate, "1", 0, "C", true, 0, "") pdf.Ln(-1) } } // Footer pdf.SetY(-25) pdf.SetFont("Arial", "I", 9) pdf.SetTextColor(128, 128, 128) pdf.Cell(0, 10, fmt.Sprintf("Casera - Tasks Report for %s", report.ResidenceName)) pdf.Ln(5) pdf.Cell(0, 10, fmt.Sprintf("Generated on %s", time.Now().UTC().Format("2006-01-02 15:04:05 UTC"))) // Output to buffer var buf bytes.Buffer if err := pdf.Output(&buf); err != nil { return nil, fmt.Errorf("failed to generate PDF: %w", err) } return buf.Bytes(), nil }