import Foundation // MARK: - Habit Frequency enum HabitFrequency: String, Codable, CaseIterable { case daily, weekly, monthly, interval, custom var displayName: String { switch self { case .daily: return "Ежедневно" case .weekly: return "Еженедельно" case .monthly: return "Ежемесячно" case .interval: return "Через N дней" case .custom: return "Особое" } } } // MARK: - Habit struct Habit: Codable, Identifiable { let id: Int var name: String var description: String? var icon: String? var color: String? var frequency: HabitFrequency var reminderTime: String? var targetDays: [Int]? var targetCount: Int? var currentStreak: Int? var longestStreak: Int? var completedToday: Bool? var totalCompleted: Int? var isArchived: Bool? var startDate: String? var createdAt: String? var updatedAt: String? var accentColorHex: String { color ?? "00d4aa" } var displayIcon: String { icon ?? "🔥" } enum CodingKeys: String, CodingKey { case id, name, description, icon, color, frequency case reminderTime = "reminder_time" case targetDays = "target_days" case targetCount = "target_count" case currentStreak = "current_streak" case longestStreak = "longest_streak" case completedToday = "completed_today" case totalCompleted = "total_completed" case isArchived = "is_archived" case startDate = "start_date" case createdAt = "created_at" case updatedAt = "updated_at" } var frequencyLabel: String { switch frequency { case .daily: return "Ежедневно" case .weekly: guard let days = targetDays, !days.isEmpty else { return "Еженедельно" } let names = ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"] return days.sorted().compactMap { names[safe: $0] }.joined(separator: ", ") case .interval: let n = targetCount ?? 1 return "Каждые \(n) дн." case .monthly: return "Ежемесячно" case .custom: return "Особое" } } } // MARK: - HabitLog struct HabitLog: Codable, Identifiable { let id: Int let habitId: Int? let completedAt: String? let note: String? var dateOnly: String { String(completedAt?.prefix(10) ?? "") } enum CodingKeys: String, CodingKey { case id case habitId = "habit_id" case completedAt = "completed_at" case note } } // MARK: - HabitFreeze struct HabitFreeze: Codable, Identifiable { let id: Int let habitId: Int? let startDate: String let endDate: String enum CodingKeys: String, CodingKey { case id case habitId = "habit_id" case startDate = "start_date" case endDate = "end_date" } } // MARK: - HabitStats struct HabitStats: Codable { let currentStreak: Int let longestStreak: Int let thisMonth: Int let totalCompleted: Int? let completionRate: Double? var completionPercent: Int { Int((completionRate ?? 0) * 100) } enum CodingKeys: String, CodingKey { case currentStreak = "current_streak" case longestStreak = "longest_streak" case thisMonth = "this_month" case totalCompleted = "total_completed" case completionRate = "completion_rate" } } // MARK: - HabitsOverallStats struct HabitsOverallStats: Codable { let todayCompleted: Int? let activeHabits: Int? enum CodingKeys: String, CodingKey { case todayCompleted = "today_completed" case activeHabits = "active_habits" } } // MARK: - CompletionDataPoint (for charts) struct CompletionDataPoint: Identifiable { let id = UUID() let date: Date let rate: Double let label: String } // MARK: - HabitLogRequest struct HabitLogRequest: Codable { var completedAt: String? var note: String? enum CodingKeys: String, CodingKey { case completedAt = "completed_at" case note } } // MARK: - Safe Array Subscript extension Array { subscript(safe index: Int) -> Element? { guard index >= 0, index < count else { return nil } return self[index] } }