package csv import ( "context" "encoding/csv" "fmt" "io" "net/http" "strconv" "strings" "github.com/paramah/ai_devs4/s01e01/internal/domain" ) // Repository implements domain.PersonRepository type Repository struct { client *http.Client } // NewRepository creates a new CSV repository func NewRepository() *Repository { return &Repository{ client: &http.Client{}, } } // FetchPeople fetches people from a CSV file at the given URL func (r *Repository) FetchPeople(ctx context.Context, url string) ([]domain.Person, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("creating request: %w", err) } resp, err := r.client.Do(req) if err != nil { return nil, fmt.Errorf("fetching CSV: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) } reader := csv.NewReader(resp.Body) // Read header header, err := reader.Read() if err != nil { return nil, fmt.Errorf("reading header: %w", err) } // Parse header to get column indices indices := make(map[string]int) for i, col := range header { indices[strings.TrimSpace(col)] = i } var people []domain.Person for { record, err := reader.Read() if err == io.EOF { break } if err != nil { return nil, fmt.Errorf("reading record: %w", err) } person, err := r.parsePerson(record, indices) if err != nil { // Skip invalid records continue } people = append(people, person) } return people, nil } func (r *Repository) parsePerson(record []string, indices map[string]int) (domain.Person, error) { var person domain.Person if idx, ok := indices["name"]; ok && idx < len(record) { person.Name = strings.TrimSpace(record[idx]) } if idx, ok := indices["surname"]; ok && idx < len(record) { person.Surname = strings.TrimSpace(record[idx]) } if idx, ok := indices["gender"]; ok && idx < len(record) { person.Gender = strings.TrimSpace(record[idx]) } // Parse birthDate (format: YYYY-MM-DD) to extract year if idx, ok := indices["birthDate"]; ok && idx < len(record) { birthDate := strings.TrimSpace(record[idx]) if len(birthDate) >= 4 { if year, err := strconv.Atoi(birthDate[:4]); err == nil { person.Born = year } } } // Use birthPlace as city if idx, ok := indices["birthPlace"]; ok && idx < len(record) { person.City = strings.TrimSpace(record[idx]) } // Read job description if idx, ok := indices["job"]; ok && idx < len(record) { person.Job = strings.TrimSpace(record[idx]) } return person, nil }