package query import ( "fmt" "log/slog" "strconv" "strings" "sync" "time" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/maximotejeda/us_dop_bot/internal/application/domain" "github.com/maximotejeda/us_dop_bot/internal/application/helpers" "github.com/maximotejeda/us_dop_bot/internal/ports" ) var chatPool *sync.Pool type Query struct { bot *tgbotapi.BotAPI update *tgbotapi.Update msg *tgbotapi.MessageConfig log *slog.Logger dolar ports.DolarService user ports.UserService } // NewQuery // Factory for query handlers func NewQuery(bot *tgbotapi.BotAPI, update *tgbotapi.Update, dolar ports.DolarService, user ports.UserService) *Query { if chatPool == nil { chatPool = &sync.Pool{ New: func() any { return &Query{} }, } for i := 0; i < 20; i++ { chatPool.Put(chatPool.New()) } } log := slog.Default() log = log.With("function", "query", "chat", update.CallbackQuery.From.ID, "userid", update.CallbackQuery.From.ID, "username", update.CallbackQuery.From.UserName) query := chatPool.Get().(*Query) query.update = update query.bot = bot query.log = log query.dolar = dolar query.user = user return query } // Empty // Returns pointer to pool func (q *Query) Empty() { q.update = nil q.msg = nil q.log = nil chatPool.Put(q) } // Send // Process Query message func (q *Query) Send() { defer q.Empty() q.bot.Send(q.msg) // Delete previous message del := tgbotapi.NewDeleteMessage(q.update.CallbackQuery.From.ID, q.update.CallbackQuery.Message.MessageID) q.bot.Send(del) } // Handler // Manage query message func (q *Query) Handler() { msg := tgbotapi.NewMessage(q.update.CallbackQuery.Message.Chat.ID, "") q.msg = &msg tUser := q.update.CallbackQuery.From data := q.update.CallbackQuery.Data dataList := strings.Split(data, "&") dataMap := map[string]string{} for _, val := range dataList { subData := strings.Split(val, "=") dataMap[subData[0]] = subData[1] } switch { case dataMap["subs"] != "": _, err := q.dolar.Subscribe(q.update.CallbackQuery.From.ID, dataMap["name"]) if err != nil { q.log.Error("subs-query", "error", err.Error(), "user", q.update.CallbackQuery.From) } case dataMap["unsubs"] != "": _, err := q.dolar.Unsubscribe(q.update.CallbackQuery.From.ID, dataMap["name"]) if err != nil { q.log.Error("subs-query", "error", err.Error(), "user", q.update.CallbackQuery.From) } case dataMap["reset"] != "": subscriptions, _ := q.dolar.GetSubscribedInsts(q.update.CallbackQuery.From.ID) if len(subscriptions) > 0 { for _, inst := range subscriptions { q.dolar.Unsubscribe(q.update.CallbackQuery.From.ID, inst) q.log.Info("unsubscribing", "institution", inst) } } case dataMap["consultar"] != "": name := "&name=" + dataMap["name"] queryMap := map[string]string{ "Actual": "query=true&time=0&unit=now" + name, //"30 Minutos": "query=true&time=30&unit=minute" + name, "1 Hora": "query=true&time=1&unit=hour" + name, "6 Horas": "query=true&time=6&unit=hour" + name, "12 Horas": "query=true&time=12&unit=hour" + name, "1 Dia": "query=true&time=24&unit=hour" + name, "1 Semana": "query=true&time=168&unit=hour" + name, "2 Semanas": "query=true&time=336&unit=hour" + name, "1 Mes": "query=true&time=672&unit=hour" + name, } keyboard := helpers.CreateKeyboard(queryMap) msg = tgbotapi.MessageConfig{} msg.ChatID = tUser.ID msg.ReplyMarkup = keyboard msg.Text = fmt.Sprintf("Intervalos de tiempo disponibles para consulta en %s el cambio del dolar desde hace:", dataMap["name"]) case dataMap["query"] != "": var timeUnit time.Duration timeAmntSTR := dataMap["time"] timeUnitSTR := dataMap["unit"] name := dataMap["name"] timeAmnt, err := strconv.Atoi(timeAmntSTR) switch name { case "apap": name = "asociacion popular de ahorros y prestamos" case "acap": name = "asociacion cibao de ahorros y prestamos" case "anap": name = "asociacion la nacional de ahorros y prestamos" case "aperap": name = "asociacion peravia de ahorros y prestamos" } if err != nil { q.log.Error("[query-query] converting amount of time to int", "error", err) q.Send() return } switch timeUnitSTR { case "hour": timeUnit = time.Hour * time.Duration(timeAmnt) instList, err := q.dolar.GetSince(name, int64(timeUnit.Minutes())) //q.log.Info("hour provided", "hour", timeUnit, "int hours", int64(timeUnit.Minutes())) if err != nil { q.log.Error("[GETLIST] querying the inst database hours", "error", err) return } queryMap := map[string]string{"clear": "cancel=true"} keyboard := helpers.CreateKeyboard(queryMap) msg = tgbotapi.MessageConfig{} msg.ChatID = tUser.ID msg.ReplyMarkup = keyboard msg.Text = instMessage(instList) case "now": instRes, err := q.dolar.GetLatest(name) if err != nil { q.log.Error("queriing the inst database now", "error", err) return } queryMap := map[string]string{"clear": "cancel=true"} keyboard := helpers.CreateKeyboard(queryMap) msg = tgbotapi.MessageConfig{} msg.ChatID = tUser.ID msg.ReplyMarkup = keyboard msg.Text = fmt.Sprintf("%s\nCompra: %.2f\nVenta: %.2f", instRes.Institution.Name, instRes.Compra, instRes.Venta) } } q.Send() } func instMessage(insts []*domain.History) string { if len(insts) <= 0 { return "Sin cambios registrados en este intervalo\nPrueba a ampliar el rango del tiempo deseado." } name := insts[0].Institution.Name resultText := fmt.Sprintf("%s\n\n", name) for _, i := range insts { date := time.Unix(i.Parsed, 0) loc, _ := time.LoadLocation("America/Santo_Domingo") resultText = resultText + fmt.Sprintf(" %s\n Compra: %.2f Venta: %.2f\n", date.In(loc).Format(time.DateTime), i.Compra, i.Venta) } return resultText }