import Foundation

// MARK: - Flexible Number Decoding

/// Decodes a JSON value that may be Int, Double, or String into a Double
struct FlexibleDouble: Decodable {
    let value: Double

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let d = try? container.decode(Double.self) {
            value = d
        } else if let i = try? container.decode(Int.self) {
            value = Double(i)
        } else if let s = try? container.decode(String.self), let d = Double(s) {
            value = d
        } else if container.decodeNil() {
            value = 0
        } else {
            value = 0
        }
    }

    init(_ v: Double) { value = v }
}

// MARK: - Food Entry (from GET /api/entries?date=...)

struct FoodEntry: Decodable, Identifiable {
    let id: String
    let userId: String?
    let foodId: String?
    let mealType: String
    let entryDate: String
    let entryType: String
    let quantity: Double
    let unit: String
    let servingDescription: String?
    let snapshotFoodName: String
    let snapshotServingLabel: String?
    let snapshotGrams: Double?
    let snapshotCalories: Double
    let snapshotProtein: Double
    let snapshotCarbs: Double
    let snapshotFat: Double
    let snapshotSugar: Double
    let snapshotFiber: Double
    let source: String
    let entryMethod: String
    let rawText: String?
    let confidenceScore: Double?
    let note: String?
    let imageRef: String?
    let aiMetadata: String?
    let idempotencyKey: String?
    let createdAt: String?
    let foodImagePath: String?

    // Computed convenience properties
    var foodName: String { snapshotFoodName }
    var calories: Double { snapshotCalories }
    var protein: Double { snapshotProtein }
    var carbs: Double { snapshotCarbs }
    var fat: Double { snapshotFat }
    var sugar: Double { snapshotSugar }
    var fiber: Double { snapshotFiber }
}

// MARK: - Daily Goal (from GET /api/goals/for-date?date=...)

struct DailyGoal: Decodable, Identifiable {
    let id: String
    let userId: String
    let startDate: String
    let endDate: String?
    let calories: Double
    let protein: Double
    let carbs: Double
    let fat: Double
    let sugar: Double
    let fiber: Double
    let isActive: Int
    let createdAt: String
}

// MARK: - Food Serving (nested in Food)

struct FoodServing: Decodable, Identifiable {
    let id: String
    let foodId: String
    let name: String
    let amountInBase: Double
    let isDefault: Int
    let createdAt: String
}

// MARK: - Food (from GET /api/foods, /api/foods/search)

struct Food: Decodable, Identifiable {
    let id: String
    let name: String
    let normalizedName: String?
    let brand: String?
    let brandNormalized: String?
    let barcode: String?
    let notes: String?
    let caloriesPerBase: Double
    let proteinPerBase: Double
    let carbsPerBase: Double
    let fatPerBase: Double
    let sugarPerBase: Double
    let fiberPerBase: Double
    let baseUnit: String
    let status: String
    let createdByUserId: String?
    let isShared: Int?
    let imagePath: String?
    let createdAt: String?
    let updatedAt: String?
    let servings: [FoodServing]?

    // Search-specific fields (only present in search results)
    let score: Double?
    let matchType: String?
}

// MARK: - Recent Food (from GET /api/foods/recent)

struct RecentFood: Decodable, Identifiable {
    let foodId: String
    let snapshotFoodName: String
    let caloriesPerBase: Double
    let proteinPerBase: Double
    let carbsPerBase: Double
    let fatPerBase: Double
    let sugarPerBase: Double
    let fiberPerBase: Double
    let baseUnit: String
    let lastUsed: String

    var id: String { foodId }
    var name: String { snapshotFoodName }
}

// MARK: - Meal Template (from GET /api/templates)

struct MealTemplate: Decodable, Identifiable {
    let id: String
    let userId: String
    let name: String
    let mealType: String?
    let isFavorite: Int
    let isArchived: Int
    let createdAt: String
    let updatedAt: String
    let items: [MealTemplateItem]
}

struct MealTemplateItem: Decodable, Identifiable {
    let id: String
    let templateId: String
    let foodId: String
    let quantity: Double
    let unit: String
    let servingDescription: String?
    let snapshotFoodName: String
    let snapshotCalories: Double
    let snapshotProtein: Double
    let snapshotCarbs: Double
    let snapshotFat: Double
    let snapshotSugar: Double
    let snapshotFiber: Double
    let createdAt: String

    var foodName: String { snapshotFoodName }
    var calories: Double { snapshotCalories }
    var protein: Double { snapshotProtein }
    var carbs: Double { snapshotCarbs }
    var fat: Double { snapshotFat }
}

// MARK: - Create Entry Request

struct CreateEntryRequest: Encodable {
    let foodId: String
    let quantity: Double
    let unit: String
    let mealType: String
    let entryDate: String
    let entryMethod: String
    let source: String
    let servingId: String?

    init(
        foodId: String,
        quantity: Double = 1.0,
        unit: String = "serving",
        mealType: String = "snack",
        entryDate: String,
        entryMethod: String = "manual",
        source: String = "ios",
        servingId: String? = nil
    ) {
        self.foodId = foodId
        self.quantity = quantity
        self.unit = unit
        self.mealType = mealType
        self.entryDate = entryDate
        self.entryMethod = entryMethod
        self.source = source
        self.servingId = servingId
    }
}

// MARK: - Update Goals Request

struct UpdateGoalsRequest: Encodable {
    let calories: Double
    let protein: Double
    let carbs: Double
    let fat: Double
    let sugar: Double
    let fiber: Double
}

// MARK: - Update Entry Request

struct UpdateEntryRequest: Encodable {
    let quantity: Double?
    let mealType: String?

    enum CodingKeys: String, CodingKey {
        case quantity
        case mealType = "meal_type"
    }
}

// MARK: - Delete Response

struct SuccessResponse: Decodable {
    let success: Bool
}

// MARK: - Template Log Response

struct TemplateLogResponse: Decodable {
    let logged: Int
    let entries: [FoodEntry]
}

// MARK: - Fitness Draft (from assistant — manual init from dictionary)

struct FitnessDraft: Identifiable {
    let id = UUID()
    var foodName: String
    var mealType: String
    var entryDate: String
    var quantity: Double
    var unit: String
    var calories: Double
    var protein: Double
    var carbs: Double
    var fat: Double
    var sugar: Double
    var fiber: Double
    var note: String
    var defaultServingLabel: String

    init(from dict: [String: Any]) {
        foodName = dict["food_name"] as? String ?? ""
        mealType = dict["meal_type"] as? String ?? "snack"
        entryDate = dict["entry_date"] as? String ?? ""
        quantity = (dict["quantity"] as? Double) ?? (dict["quantity"] as? Int).map(Double.init) ?? 1.0
        unit = dict["unit"] as? String ?? "serving"
        calories = (dict["calories"] as? Double) ?? (dict["calories"] as? Int).map(Double.init) ?? 0
        protein = (dict["protein"] as? Double) ?? (dict["protein"] as? Int).map(Double.init) ?? 0
        carbs = (dict["carbs"] as? Double) ?? (dict["carbs"] as? Int).map(Double.init) ?? 0
        fat = (dict["fat"] as? Double) ?? (dict["fat"] as? Int).map(Double.init) ?? 0
        sugar = (dict["sugar"] as? Double) ?? (dict["sugar"] as? Int).map(Double.init) ?? 0
        fiber = (dict["fiber"] as? Double) ?? (dict["fiber"] as? Int).map(Double.init) ?? 0
        note = dict["note"] as? String ?? ""
        defaultServingLabel = dict["default_serving_label"] as? String ?? ""
    }
}

// MARK: - Meal Type Helpers

enum MealType: String, CaseIterable {
    case breakfast, lunch, dinner, snack

    var displayName: String {
        rawValue.capitalized
    }

    var icon: String {
        switch self {
        case .breakfast: return "sunrise.fill"
        case .lunch: return "sun.max.fill"
        case .dinner: return "moon.stars.fill"
        case .snack: return "leaf.fill"
        }
    }

    var sortOrder: Int {
        switch self {
        case .breakfast: return 0
        case .lunch: return 1
        case .dinner: return 2
        case .snack: return 3
        }
    }
}
