package report import ( "context" "encoding/csv" "errors" "fmt" "os" "path/filepath" "time" "reflect" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/google/uuid" "go.uber.org/zap" ) var ( ErrReportFileNotFound = errors.New("failed to find report file") ErrReportFileError = errors.New("unknown error with report file") ErrReportNotComplete = errors.New("report is not completed") ErrReportFilePathInvalid = errors.New("report file path is invalid") ) func StructToCSVRow(v any) ([]string, []string) { t := reflect.TypeOf(v) val := reflect.ValueOf(v) headers := make([]string, t.NumField()) row := make([]string, t.NumField()) for i := 0; i < t.NumField(); i++ { field := t.Field(i) headers[i] = field.Tag.Get("csv") row[i] = fmt.Sprint(val.Field(i).Interface()) } return headers, row } func (s *Service) WriteCSV(rows [][]string, filePrefix string) (string, error) { if len(rows) == 0 { s.mongoLogger.Error("[WriteCSV] CSV with no data", zap.String("file_prefix", filePrefix), ) return "", errors.New("no data to write") } filename := fmt.Sprintf("%s_%s_%s.csv", filePrefix, time.Now().Format("2006-01-02_15-04-05"), uuid.NewString()[:8], ) filePath := filepath.Join(s.cfg.ReportExportPath, filename) file, err := os.Create(filePath) if err != nil { s.mongoLogger.Error("[WriteCSV] Failed to create file", zap.String("file", filename), zap.String("path", s.cfg.ReportExportPath), zap.Error(err), ) return "", fmt.Errorf("create csv: %w", err) } defer file.Close() writer := csv.NewWriter(file) if err := writer.WriteAll(rows); err != nil { s.mongoLogger.Error("[WriteCSV] Error while writing csv", zap.String("file", filename), zap.String("path", s.cfg.ReportExportPath), zap.Error(err), ) return "", fmt.Errorf("write csv: %w", err) } return filePath, nil } func (s *Service) CheckAndFetchReportFile(ctx context.Context, ID int64) (string, error) { report, err := s.GetReportRequestByID(ctx, ID) if err != nil { s.mongoLogger.Error("[CheckAndFetchReportFile] Failed to get report request by id", zap.Error(err), ) return "", fmt.Errorf("failed to get report request:%w", err) } if report.Status != domain.SuccessReportRequest { s.mongoLogger.Error("[CheckAndFetchReportFile] Attempted download of report that isn't completed", zap.String("status", string(report.Status)), ) return "", ErrReportNotComplete } if !report.FilePath.Valid { s.mongoLogger.Error("[CheckAndFetchReportFile] File Path is invalid even though the report is a success", zap.String("file path", report.FilePath.Value), ) return "", ErrReportFilePathInvalid } // Check if the report file exists if _, err := os.Stat(report.FilePath.Value); err != nil { if os.IsNotExist(err) { s.mongoLogger.Error("[CheckAndFetchReportFile] Unable to find report file", zap.String("file path", report.FilePath.Value), ) return "", ErrReportFileNotFound } s.mongoLogger.Error("[CheckAndFetchReportFile] Unable to check report file", zap.String("file path", report.FilePath.Value), zap.Error(err), ) return "", ErrReportFileError } return report.FilePath.Value, nil }