package handlers import ( "context" "fmt" "os" "strconv" "strings" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/gofiber/fiber/v2" ) // GetDashboardReport returns a comprehensive dashboard report // @Summary Get dashboard report // @Description Returns a comprehensive dashboard report with key metrics // @Tags Reports // @Accept json // @Produce json // @Param company_id query int false "Company ID filter" // @Param branch_id query int false "Branch ID filter" // @Param user_id query int false "User ID filter" // @Param start_time query string false "Start time filter (RFC3339 format)" // @Param end_time query string false "End time filter (RFC3339 format)" // @Param sport_id query string false "Sport ID filter" // @Param status query int false "Status filter (0=Pending, 1=Win, 2=Loss, 3=Half, 4=Void, 5=Error)" // @Security ApiKeyAuth // @Success 200 {object} domain.DashboardSummary // @Failure 400 {object} domain.ErrorResponse // @Failure 401 {object} domain.ErrorResponse // @Failure 500 {object} domain.ErrorResponse // @Router /api/v1/reports/dashboard [get] func (h *Handler) GetDashboardReport(c *fiber.Ctx) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // Parse query parameters filter, err := parseReportFilter(c) if err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid filter parameters", Error: err.Error(), }) } // Get report data summary, err := h.reportSvc.GetDashboardSummary(ctx, filter) if err != nil { h.logger.Error("failed to get dashboard report", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ Message: "Failed to generate report", Error: err.Error(), }) } return c.Status(fiber.StatusOK).JSON(domain.Response{ Message: "Dashboard reports generated successfully", Success: true, StatusCode: 200, Data: summary, }) // return c.Status(fiber.StatusOK).JSON(summary) } // parseReportFilter parses query parameters into ReportFilter func parseReportFilter(c *fiber.Ctx) (domain.ReportFilter, error) { var filter domain.ReportFilter var err error if c.Query("company_id") != "" { companyID, err := strconv.ParseInt(c.Query("company_id"), 10, 64) if err != nil { return domain.ReportFilter{}, fmt.Errorf("invalid company_id: %w", err) } filter.CompanyID = domain.ValidInt64{Value: companyID, Valid: true} } if c.Query("branch_id") != "" { branchID, err := strconv.ParseInt(c.Query("branch_id"), 10, 64) if err != nil { return domain.ReportFilter{}, fmt.Errorf("invalid branch_id: %w", err) } filter.BranchID = domain.ValidInt64{Value: branchID, Valid: true} } if c.Query("user_id") != "" { userID, err := strconv.ParseInt(c.Query("user_id"), 10, 64) if err != nil { return domain.ReportFilter{}, fmt.Errorf("invalid user_id: %w", err) } filter.UserID = domain.ValidInt64{Value: userID, Valid: true} } if c.Query("start_time") != "" { startTime, err := time.Parse(time.RFC3339, c.Query("start_time")) if err != nil { return domain.ReportFilter{}, fmt.Errorf("invalid start_time: %w", err) } filter.StartTime = domain.ValidTime{Value: startTime, Valid: true} } if c.Query("end_time") != "" { endTime, err := time.Parse(time.RFC3339, c.Query("end_time")) if err != nil { return domain.ReportFilter{}, fmt.Errorf("invalid end_time: %w", err) } filter.EndTime = domain.ValidTime{Value: endTime, Valid: true} } if c.Query("sport_id") != "" { filter.SportID = domain.ValidString{Value: c.Query("sport_id"), Valid: true} } if c.Query("status") != "" { status, err := strconv.ParseInt(c.Query("status"), 10, 32) if err != nil { return domain.ReportFilter{}, fmt.Errorf("invalid status: %w", err) } filter.Status = domain.ValidOutcomeStatus{Value: domain.OutcomeStatus(status), Valid: true} } return filter, err } // DownloadReportFile godoc // @Summary Download a CSV report file // @Description Downloads a generated report CSV file from the server // @Tags Reports // @Param filename path string true "Name of the report file to download (e.g., report_daily_2025-06-21.csv)" // @Produce text/csv // @Success 200 {file} file "CSV file will be downloaded" // @Failure 400 {object} domain.ErrorResponse "Missing or invalid filename" // @Failure 404 {object} domain.ErrorResponse "Report file not found" // @Failure 500 {object} domain.ErrorResponse "Internal server error while serving the file" // @Router /api/v1/report-files/download/{filename} [get] func (h *Handler) DownloadReportFile(c *fiber.Ctx) error { filename := c.Params("filename") if filename == "" { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Missing filename parameter", Error: "filename is required", }) } filePath := fmt.Sprintf("/host-desktop/%s", filename) // Check if file exists if _, err := os.Stat(filePath); os.IsNotExist(err) { return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{ Message: "Report file not found", Error: "no such file", }) } // Set download headers and return file c.Set("Content-Type", "text/csv") c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) if err := c.SendFile(filePath); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ Message: "Failed to serve file", Error: err.Error(), }) } return nil } // ListReportFiles godoc // @Summary List available report CSV files // @Description Returns a list of all generated report CSV files available for download // @Tags Reports // @Produce json // @Success 200 {object} domain.Response{data=[]string} "List of CSV report filenames" // @Failure 500 {object} domain.ErrorResponse "Failed to read report directory" // @Router /api/v1/report-files/list [get] func (h *Handler) ListReportFiles(c *fiber.Ctx) error { reportDir := "/host-desktop" files, err := os.ReadDir(reportDir) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ Message: "Failed to read report directory", Error: err.Error(), }) } var reportFiles []string for _, file := range files { if !file.IsDir() && strings.HasSuffix(file.Name(), ".csv") { reportFiles = append(reportFiles, file.Name()) } } return c.Status(fiber.StatusOK).JSON(domain.Response{ StatusCode: 200, Message: "Report files retrieved successfully", Data: reportFiles, Success: true, }) }