package bot import ( "fmt" "strconv" "strings" "time" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/daniil/homelab-api/internal/model" "github.com/daniil/homelab-api/internal/repository" ) func (b *Bot) handleMessage(msg *tgbotapi.Message) { if !msg.IsCommand() { return } cmd := msg.Command() // Handle commands like /done_123 or /check_123 if strings.HasPrefix(cmd, "done_") { b.handleDoneByID(msg, strings.TrimPrefix(cmd, "done_")) return } if strings.HasPrefix(cmd, "check_") { b.handleCheckByID(msg, strings.TrimPrefix(cmd, "check_")) return } switch cmd { case "start": b.handleStart(msg) case "tasks": b.handleTasks(msg) case "habits": b.handleHabits(msg) case "done": b.handleDone(msg) case "check": b.handleCheck(msg) case "help": b.handleHelp(msg) } } func (b *Bot) handleCallback(callback *tgbotapi.CallbackQuery) { data := callback.Data chatID := callback.Message.Chat.ID messageID := callback.Message.MessageID user, err := b.userRepo.GetByTelegramChatID(chatID) if err != nil { b.answerCallback(callback.ID, "❌ Аккаунт не найден") return } parts := strings.Split(data, "_") if len(parts) < 2 { return } action := parts[0] id, _ := strconv.ParseInt(parts[1], 10, 64) switch action { case "donetask": err = b.taskRepo.Complete(id, user.ID) if err != nil { b.answerCallback(callback.ID, "❌ Ошибка") return } b.answerCallback(callback.ID, "✅ Задача выполнена!") b.refreshTasksMessage(chatID, messageID, user.ID) case "deltask": err = b.taskRepo.Delete(id, user.ID) if err != nil { b.answerCallback(callback.ID, "❌ Ошибка") return } b.answerCallback(callback.ID, "🗑 Задача удалена") b.refreshTasksMessage(chatID, messageID, user.ID) case "checkhabit": log := &model.HabitLog{ HabitID: id, UserID: user.ID, Date: time.Now(), Count: 1, } err = b.habitRepo.CreateLog(log) if err != nil { b.answerCallback(callback.ID, "❌ Ошибка") return } b.answerCallback(callback.ID, "✅ Привычка отмечена!") b.refreshHabitsMessage(chatID, messageID, user.ID) } } func (b *Bot) answerCallback(callbackID, text string) { callback := tgbotapi.NewCallback(callbackID, text) b.api.Request(callback) } func (b *Bot) refreshTasksMessage(chatID int64, messageID int, userID int64) { tasks, err := b.taskRepo.GetTodayTasks(userID) if err != nil { return } text, keyboard := b.buildTasksMessage(tasks) edit := tgbotapi.NewEditMessageText(chatID, messageID, text) edit.ParseMode = "HTML" if keyboard != nil { edit.ReplyMarkup = keyboard } b.api.Send(edit) } func (b *Bot) refreshHabitsMessage(chatID int64, messageID int, userID int64) { habits, _ := b.habitRepo.ListByUser(userID, false) text, keyboard := b.buildHabitsMessage(habits, userID) edit := tgbotapi.NewEditMessageText(chatID, messageID, text) edit.ParseMode = "HTML" if keyboard != nil { edit.ReplyMarkup = keyboard } b.api.Send(edit) } func (b *Bot) buildTasksMessage(tasks []model.Task) (string, *tgbotapi.InlineKeyboardMarkup) { if len(tasks) == 0 { return "✨ На сегодня задач нет!", nil } text := "📋 Задачи на сегодня:\n\n" var rows [][]tgbotapi.InlineKeyboardButton for _, task := range tasks { priority := "" switch task.Priority { case 3: priority = "🔴 " case 2: priority = "🟡 " case 1: priority = "🔵 " } status := "⬜" if task.CompletedAt.Valid { status = "✅" } text += fmt.Sprintf("%s %s%s %s\n", status, priority, task.Icon, task.Title) if task.Description != "" { text += fmt.Sprintf(" %s\n", task.Description) } text += "\n" // Add buttons only for incomplete tasks if !task.CompletedAt.Valid { row := []tgbotapi.InlineKeyboardButton{ tgbotapi.NewInlineKeyboardButtonData("✅ Выполнить", fmt.Sprintf("donetask_%d", task.ID)), tgbotapi.NewInlineKeyboardButtonData("🗑 Удалить", fmt.Sprintf("deltask_%d", task.ID)), } rows = append(rows, row) } } if len(rows) == 0 { return text, nil } keyboard := tgbotapi.NewInlineKeyboardMarkup(rows...) return text, &keyboard } func (b *Bot) buildHabitsMessage(habits []model.Habit, userID int64) (string, *tgbotapi.InlineKeyboardMarkup) { today := int(time.Now().Weekday()) var todayHabits []model.Habit for _, habit := range habits { if habit.Frequency == "daily" { todayHabits = append(todayHabits, habit) } else { for _, day := range habit.TargetDays { if day == today { todayHabits = append(todayHabits, habit) break } } } } if len(todayHabits) == 0 { return "✨ На сегодня привычек нет!", nil } text := "🎯 Привычки на сегодня:\n\n" var rows [][]tgbotapi.InlineKeyboardButton for _, habit := range todayHabits { completed, _ := b.habitRepo.IsHabitCompletedToday(habit.ID, userID) status := "⬜" if completed { status = "✅" } text += fmt.Sprintf("%s %s %s\n", status, habit.Icon, habit.Name) if habit.Description != "" { text += fmt.Sprintf(" %s\n", habit.Description) } text += "\n" if !completed { row := []tgbotapi.InlineKeyboardButton{ tgbotapi.NewInlineKeyboardButtonData(fmt.Sprintf("✅ %s", habit.Name), fmt.Sprintf("checkhabit_%d", habit.ID)), } rows = append(rows, row) } } if len(rows) == 0 { return text, nil } keyboard := tgbotapi.NewInlineKeyboardMarkup(rows...) return text, &keyboard } func (b *Bot) handleStart(msg *tgbotapi.Message) { text := fmt.Sprintf(`👋 Привет! Я бот Pulse. Твой Chat ID: %d Скопируй его и вставь в настройках Pulse для получения уведомлений. Доступные команды: /tasks — задачи на сегодня /habits — привычки на сегодня /help — справка`, msg.Chat.ID) b.SendMessage(msg.Chat.ID, text) } func (b *Bot) handleHelp(msg *tgbotapi.Message) { text := `📚 Справка по командам: /start — получить твой Chat ID /tasks — список задач на сегодня /habits — список привычек 💡 Чтобы получать уведомления, добавь свой Chat ID в настройках Pulse.` b.SendMessage(msg.Chat.ID, text) } func (b *Bot) handleTasks(msg *tgbotapi.Message) { user, err := b.userRepo.GetByTelegramChatID(msg.Chat.ID) if err != nil { if err == repository.ErrUserNotFound { b.SendMessage(msg.Chat.ID, "❌ Аккаунт не найден. Добавь свой Chat ID в настройках Pulse.") return } b.SendMessage(msg.Chat.ID, "❌ Ошибка при получении данных") return } tasks, err := b.taskRepo.GetTodayTasks(user.ID) if err != nil { b.SendMessage(msg.Chat.ID, "❌ Ошибка при получении задач") return } text, keyboard := b.buildTasksMessage(tasks) b.SendMessageWithKeyboard(msg.Chat.ID, text, keyboard) } func (b *Bot) handleHabits(msg *tgbotapi.Message) { user, err := b.userRepo.GetByTelegramChatID(msg.Chat.ID) if err != nil { if err == repository.ErrUserNotFound { b.SendMessage(msg.Chat.ID, "❌ Аккаунт не найден. Добавь свой Chat ID в настройках Pulse.") return } b.SendMessage(msg.Chat.ID, "❌ Ошибка при получении данных") return } habits, err := b.habitRepo.ListByUser(user.ID, false) if err != nil { b.SendMessage(msg.Chat.ID, "❌ Ошибка при получении привычек") return } text, keyboard := b.buildHabitsMessage(habits, user.ID) b.SendMessageWithKeyboard(msg.Chat.ID, text, keyboard) } func (b *Bot) handleDone(msg *tgbotapi.Message) { args := msg.CommandArguments() if args == "" { b.SendMessage(msg.Chat.ID, "❌ Укажи ID задачи: /done ") return } b.handleDoneByID(msg, args) } func (b *Bot) handleDoneByID(msg *tgbotapi.Message, idStr string) { user, err := b.userRepo.GetByTelegramChatID(msg.Chat.ID) if err != nil { b.SendMessage(msg.Chat.ID, "❌ Аккаунт не найден") return } taskID, _ := strconv.ParseInt(idStr, 10, 64) if taskID == 0 { b.SendMessage(msg.Chat.ID, "❌ Неверный ID задачи") return } err = b.taskRepo.Complete(taskID, user.ID) if err != nil { if err == repository.ErrTaskNotFound { b.SendMessage(msg.Chat.ID, "❌ Задача не найдена") return } b.SendMessage(msg.Chat.ID, "❌ Ошибка при выполнении задачи") return } b.SendMessage(msg.Chat.ID, "✅ Задача выполнена!") } func (b *Bot) handleCheck(msg *tgbotapi.Message) { args := msg.CommandArguments() if args == "" { b.SendMessage(msg.Chat.ID, "❌ Укажи ID привычки: /check ") return } b.handleCheckByID(msg, args) } func (b *Bot) handleCheckByID(msg *tgbotapi.Message, idStr string) { user, err := b.userRepo.GetByTelegramChatID(msg.Chat.ID) if err != nil { b.SendMessage(msg.Chat.ID, "❌ Аккаунт не найден") return } habitID, _ := strconv.ParseInt(idStr, 10, 64) if habitID == 0 { b.SendMessage(msg.Chat.ID, "❌ Неверный ID привычки") return } _, err = b.habitRepo.GetByID(habitID, user.ID) if err != nil { if err == repository.ErrHabitNotFound { b.SendMessage(msg.Chat.ID, "❌ Привычка не найдена") return } b.SendMessage(msg.Chat.ID, "❌ Ошибка при получении привычки") return } log := &model.HabitLog{ HabitID: habitID, UserID: user.ID, Date: time.Now(), Count: 1, } err = b.habitRepo.CreateLog(log) if err != nil { b.SendMessage(msg.Chat.ID, "❌ Ошибка при отметке привычки") return } b.SendMessage(msg.Chat.ID, "✅ Привычка отмечена!") }