package bot import ( "context" "fmt" "strconv" "strings" "time" "github.com/go-telegram/bot/models" "worktimeBot/internal/db" ) // handleSetReportTime parses a HH:MM argument and updates the user's report time. func (h *Handler) handleSetReportTime(ctx context.Context, msg *models.Message) { args := "" if len(msg.Text) > 16 { // "/setreporttime " is 15 chars args = strings.TrimSpace(msg.Text[15:]) } if args == "" { user, err := h.getOrCreateUser(msg.Chat.ID) if err != nil { h.sendText(ctx, msg.Chat.ID, "Error loading profile") return } h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Current report time: %s\nUsage: /setreporttime HH:MM (24-hour)", user.ReportTime)) return } if len(args) != 5 || args[2] != ':' { h.sendText(ctx, msg.Chat.ID, "Invalid format. Usage: /setreporttime HH:MM (24-hour)") return } hours, err1 := strconv.Atoi(args[:2]) mins, err2 := strconv.Atoi(args[3:]) if err1 != nil || err2 != nil || hours < 0 || hours > 23 || mins < 0 || mins > 59 { h.sendText(ctx, msg.Chat.ID, "Invalid time. Usage: /setreporttime HH:MM (24-hour)") return } user, err := h.getOrCreateUser(msg.Chat.ID) if err != nil { h.sendText(ctx, msg.Chat.ID, "Error updating report time") return } user.ReportTime = args if err := h.DB.UpdateUser(user); err != nil { h.sendText(ctx, msg.Chat.ID, "Error updating report time") return } h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Report time set to %s", args)) } // handleAccentMsg shows the accent color picker. func (h *Handler) handleAccentMsg(ctx context.Context, msg *models.Message) { user, err := h.getOrCreateUser(msg.Chat.ID) if err != nil { h.sendText(ctx, msg.Chat.ID, "Error loading profile") return } text, kb := h.buildAccentKeyboard(user) h.sendWithKB(ctx, msg.Chat.ID, text, kb) } // handleSetTimezone validates and updates the user's IANA timezone. func (h *Handler) handleSetTimezone(ctx context.Context, msg *models.Message) { args := "" if len(msg.Text) > 13 { // "/settimezone " is 12 chars args = strings.TrimSpace(msg.Text[13:]) } if args == "" { user, err := h.getOrCreateUser(msg.Chat.ID) if err != nil { h.sendText(ctx, msg.Chat.ID, "Error loading profile") return } h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Current timezone: %s\nUsage: /settimezone \nExamples: Asia/Tehran, Europe/London, America/New_York", user.Timezone)) return } loc, err := time.LoadLocation(args) if err != nil { h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Invalid timezone: %s\nUse IANA format, e.g. Asia/Tehran, Europe/London", args)) return } user, err := h.getOrCreateUser(msg.Chat.ID) if err != nil { h.sendText(ctx, msg.Chat.ID, "Error loading profile") return } user.Timezone = args if err := h.DB.UpdateUser(user); err != nil { h.sendText(ctx, msg.Chat.ID, "Error saving timezone") return } now := time.Now().In(loc) h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Timezone set to %s (current time: %s)", args, now.Format("15:04"))) } // settingsCallback shows the settings inline menu. func (h *Handler) settingsCallback(ctx context.Context, chatID int64, msgID int, callbackID string) { h.answerCb(ctx, callbackID) user, err := h.getOrCreateUser(chatID) if err != nil { return } text, kb := h.buildSettingsKeyboard(user) h.editText(ctx, chatID, msgID, text, &kb) } // buildSettingsKeyboard returns the settings menu text and inline keyboard. func (h *Handler) buildSettingsKeyboard(user *db.User) (string, models.InlineKeyboardMarkup) { reportStatus := "disabled" if user.ReportEnabled { reportStatus = "enabled" } rows := [][]models.InlineKeyboardButton{ {{Text: fmt.Sprintf("Timezone: %s", user.Timezone), CallbackData: "timezone"}}, {{Text: fmt.Sprintf("Accent: %s", user.ExportAccent), CallbackData: "accent"}}, {{Text: fmt.Sprintf("Calendar: %s", user.Calendar), CallbackData: "caltype"}}, {{Text: fmt.Sprintf("Report: %s", reportStatus), CallbackData: "reporttoggle"}}, {{Text: fmt.Sprintf("Report time: %s", user.ReportTime), CallbackData: "reporttime"}}, {{Text: "History", CallbackData: "history"}}, {{Text: "Back to Menu", CallbackData: "back_menu"}}, } return "Settings:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } // accentCallback shows the accent color picker (inline edit). func (h *Handler) accentCallback(ctx context.Context, chatID int64, msgID int, callbackID string) { h.answerCb(ctx, callbackID) user, err := h.getOrCreateUser(chatID) if err != nil { return } text, kb := h.buildAccentKeyboard(user) h.editText(ctx, chatID, msgID, text, &kb) } // timezoneCallback shows the current timezone and instructions to change it. func (h *Handler) timezoneCallback(ctx context.Context, chatID int64, msgID int, callbackID string) { h.answerCb(ctx, callbackID) user, err := h.getOrCreateUser(chatID) if err != nil { return } text := fmt.Sprintf("Current timezone: %s\n\nUse /settimezone to change it.\nExamples: Asia/Tehran, Europe/London, America/New_York", user.Timezone) kb := models.InlineKeyboardMarkup{ InlineKeyboard: [][]models.InlineKeyboardButton{ {{Text: "Back to Settings", CallbackData: "back_settings"}}, }, } h.editText(ctx, chatID, msgID, text, &kb) } // buildAccentKeyboard returns the accent color picker keyboard. func (h *Handler) buildAccentKeyboard(user *db.User) (string, models.InlineKeyboardMarkup) { type accentOption struct { name string color string } accents := []accentOption{ {"ocean", "Blue"}, {"beach", "Warm"}, {"rose", "Pink"}, {"catppuccin", "Purple"}, } rows := [][]models.InlineKeyboardButton{} for _, a := range accents { label := fmt.Sprintf("%s (%s)", a.name, a.color) if a.name == user.ExportAccent { label = "> " + label } rows = append(rows, []models.InlineKeyboardButton{ {Text: label, CallbackData: "accent_" + a.name}, }) } rows = append(rows, []models.InlineKeyboardButton{ {Text: "Back to Settings", CallbackData: "back_settings"}, }) return "Select accent color:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } // selectAccent sets the user's export accent color after validation. func (h *Handler) selectAccent(ctx context.Context, chatID int64, msgID int, callbackID, name string) { h.answerCb(ctx, callbackID) user, err := h.getOrCreateUser(chatID) if err != nil { return } valid := map[string]bool{"ocean": true, "beach": true, "rose": true, "catppuccin": true} if !valid[name] { return } user.ExportAccent = name if err := h.DB.UpdateUser(user); err != nil { return } kb := models.InlineKeyboardMarkup{ InlineKeyboard: [][]models.InlineKeyboardButton{ {{Text: "Back to Settings", CallbackData: "back_settings"}}, }, } h.editText(ctx, chatID, msgID, fmt.Sprintf("Accent set to: %s", name), &kb) } // reportTimeCallback shows the current report time setting. func (h *Handler) reportTimeCallback(ctx context.Context, chatID int64, msgID int, callbackID string) { h.answerCb(ctx, callbackID) user, err := h.getOrCreateUser(chatID) if err != nil { return } text := fmt.Sprintf("Current report time: %s\nUse /setreporttime HH:MM to change it.", user.ReportTime) kb := models.InlineKeyboardMarkup{ InlineKeyboard: [][]models.InlineKeyboardButton{ {{Text: "Back to Settings", CallbackData: "back_settings"}}, }, } h.editText(ctx, chatID, msgID, text, &kb) } // backToSettings returns to the main settings menu. func (h *Handler) backToSettings(ctx context.Context, chatID int64, msgID int, callbackID string) { h.answerCb(ctx, callbackID) user, err := h.getOrCreateUser(chatID) if err != nil { return } text, kb := h.buildSettingsKeyboard(user) h.editText(ctx, chatID, msgID, text, &kb) } // calTypeCallback shows the calendar type selector. func (h *Handler) calTypeCallback(ctx context.Context, chatID int64, msgID int, callbackID string) { h.answerCb(ctx, callbackID) user, err := h.getOrCreateUser(chatID) if err != nil { return } text, kb := h.buildCalendarKeyboard(user) h.editText(ctx, chatID, msgID, text, &kb) } // buildCalendarKeyboard returns the calendar type selector keyboard. func (h *Handler) buildCalendarKeyboard(user *db.User) (string, models.InlineKeyboardMarkup) { cals := []string{"gregorian", "jalali", "hijri"} calLabels := map[string]string{ "gregorian": "Gregorian", "jalali": "Jalali", "hijri": "Hijri", } rows := [][]models.InlineKeyboardButton{} for _, c := range cals { label := calLabels[c] if c == user.Calendar { label = "> " + label } rows = append(rows, []models.InlineKeyboardButton{ {Text: label, CallbackData: "caltype_" + c}, }) } rows = append(rows, []models.InlineKeyboardButton{ {Text: "Back to Settings", CallbackData: "back_settings"}, }) return "Select calendar type:", models.InlineKeyboardMarkup{InlineKeyboard: rows} } // selectCalendar sets the user's calendar after validation. func (h *Handler) selectCalendar(ctx context.Context, chatID int64, msgID int, callbackID, name string) { h.answerCb(ctx, callbackID) valid := map[string]bool{"gregorian": true, "jalali": true, "hijri": true} if !valid[name] { return } user, err := h.getOrCreateUser(chatID) if err != nil { return } user.Calendar = name if err := h.DB.UpdateUser(user); err != nil { return } text, kb := h.buildSettingsKeyboard(user) h.editText(ctx, chatID, msgID, text, &kb) }