summaryrefslogtreecommitdiff
path: root/internal/api/plantoeat.go
blob: eb29c63b499b977add57fe1f1b1160732cba8d23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package api

import (
	"context"
	"fmt"
	"time"

	"task-dashboard/internal/models"
)

const planToEatBaseURL = "https://www.plantoeat.com/api/v2"

// PlanToEatClient handles interactions with the PlanToEat API
type PlanToEatClient struct {
	BaseClient
	apiKey string
}

// NewPlanToEatClient creates a new PlanToEat API client
func NewPlanToEatClient(apiKey string) *PlanToEatClient {
	return &PlanToEatClient{
		BaseClient: NewBaseClient(planToEatBaseURL),
		apiKey:     apiKey,
	}
}

func (c *PlanToEatClient) authHeaders() map[string]string {
	return map[string]string{"Authorization": "Bearer " + c.apiKey}
}

// planToEatPlannerItem represents a planner item from the API
type planToEatPlannerItem struct {
	ID       int    `json:"id"`
	Date     string `json:"date"`
	MealType string `json:"meal_type"`
	Recipe   struct {
		ID    int    `json:"id"`
		Title string `json:"title"`
		URL   string `json:"url"`
	} `json:"recipe"`
}

// planToEatResponse wraps the API response
type planToEatResponse struct {
	Items []planToEatPlannerItem `json:"items"`
}

// GetUpcomingMeals fetches meals for the next N days
func (c *PlanToEatClient) GetUpcomingMeals(ctx context.Context, days int) ([]models.Meal, error) {
	if days <= 0 {
		days = 7
	}

	startDate := time.Now()
	endDate := startDate.AddDate(0, 0, days)

	path := fmt.Sprintf("/planner_items?start_date=%s&end_date=%s",
		startDate.Format("2006-01-02"),
		endDate.Format("2006-01-02"))

	var apiResponse planToEatResponse
	if err := c.Get(ctx, path, c.authHeaders(), &apiResponse); err != nil {
		return nil, fmt.Errorf("failed to fetch meals: %w", err)
	}

	meals := make([]models.Meal, 0, len(apiResponse.Items))
	for _, item := range apiResponse.Items {
		mealDate, err := time.Parse("2006-01-02", item.Date)
		if err != nil {
			continue
		}

		meals = append(meals, models.Meal{
			ID:         fmt.Sprintf("%d", item.ID),
			RecipeName: item.Recipe.Title,
			Date:       mealDate,
			MealType:   normalizeMealType(item.MealType),
			RecipeURL:  item.Recipe.URL,
		})
	}

	return meals, nil
}

// normalizeMealType ensures meal type matches our expected values
func normalizeMealType(mealType string) string {
	switch mealType {
	case "breakfast", "Breakfast":
		return "breakfast"
	case "lunch", "Lunch":
		return "lunch"
	case "dinner", "Dinner":
		return "dinner"
	case "snack", "Snack":
		return "snack"
	default:
		return "dinner"
	}
}

// GetRecipes fetches recipes (for Phase 2)
func (c *PlanToEatClient) GetRecipes(ctx context.Context) error {
	return fmt.Errorf("not implemented yet")
}

// AddMealToPlanner adds a meal to the planner (for Phase 2)
func (c *PlanToEatClient) AddMealToPlanner(ctx context.Context, recipeID string, date time.Time, mealType string) error {
	return fmt.Errorf("not implemented yet")
}