import Foundation

@MainActor @Observable
final class TodayViewModel {
    var entries: [FoodEntry] = []
    var goal: DailyGoal = .defaultGoal
    var selectedDate: Date = Date()
    var isLoading = true
    var errorMessage: String?
    var expandedMeals: Set<String> = Set(MealType.allCases.map(\.rawValue))

    private let repo = FitnessRepository.shared

    // MARK: - Computed Properties

    var dateString: String {
        selectedDate.apiDateString
    }

    var mealGroups: [MealGroup] {
        MealType.allCases.map { meal in
            MealGroup(
                meal: meal,
                entries: entries.filter { $0.mealType == meal.rawValue }
            )
        }
    }

    var totalCalories: Double {
        entries.reduce(0) { $0 + $1.calories }
    }

    var totalProtein: Double {
        entries.reduce(0) { $0 + $1.protein }
    }

    var totalCarbs: Double {
        entries.reduce(0) { $0 + $1.carbs }
    }

    var totalFat: Double {
        entries.reduce(0) { $0 + $1.fat }
    }

    var caloriesRemaining: Double {
        max(goal.calories - totalCalories, 0)
    }

    // MARK: - Actions

    func load() async {
        isLoading = true
        errorMessage = nil

        do {
            async let entriesTask = repo.entries(for: dateString, forceRefresh: true)
            async let goalsTask = repo.goals(for: dateString)

            entries = try await entriesTask
            goal = try await goalsTask
        } catch {
            errorMessage = error.localizedDescription
        }

        isLoading = false
    }

    func goToNextDay() {
        selectedDate = selectedDate.adding(days: 1)
        Task { await load() }
    }

    func goToPreviousDay() {
        selectedDate = selectedDate.adding(days: -1)
        Task { await load() }
    }

    func goToToday() {
        selectedDate = Date()
        Task { await load() }
    }

    func toggleMeal(_ meal: String) {
        if expandedMeals.contains(meal) {
            expandedMeals.remove(meal)
        } else {
            expandedMeals.insert(meal)
        }
    }

    func deleteEntry(_ entry: FoodEntry) async {
        // Optimistic removal
        entries.removeAll { $0.id == entry.id }
        do {
            try await repo.deleteEntry(id: entry.id, date: dateString)
        } catch {
            // Reload on failure
            await load()
        }
    }

    func updateEntryQuantity(id: String, quantity: Double) async {
        let request = UpdateEntryRequest(quantity: quantity)
        do {
            _ = try await repo.updateEntry(id: id, request: request, date: dateString)
            await load()
        } catch {
            errorMessage = "Failed to update entry"
        }
    }
}
