package usecase import ( "context" "fmt" "log/slog" "time" "github.com/google/uuid" "github.com/paramah/gw_telegram/internal/application/dto" "github.com/paramah/gw_telegram/internal/domain/apperror" "github.com/paramah/gw_telegram/internal/domain/entity" "github.com/paramah/gw_telegram/internal/domain/port" ) type HandleTextMessage struct { router port.IntentRouter dispatcher port.WorkflowDispatcher sessions port.SessionStore gateway port.MessageGateway logger *slog.Logger } func NewHandleTextMessage( router port.IntentRouter, dispatcher port.WorkflowDispatcher, sessions port.SessionStore, gateway port.MessageGateway, logger *slog.Logger, ) *HandleTextMessage { return &HandleTextMessage{ router: router, dispatcher: dispatcher, sessions: sessions, gateway: gateway, logger: logger, } } func (h *HandleTextMessage) Execute(ctx context.Context, in dto.IncomingMessageDTO) error { if in.Text == "" { return apperror.ErrMessageEmpty } msg := entity.Message{ MessageID: in.MessageID, ChatID: in.ChatID, UserID: in.UserID, Username: in.Username, Type: entity.MessageTypeText, Text: in.Text, Timestamp: in.Timestamp, Metadata: map[string]any{"language": in.Language}, } session, err := h.sessions.Get(ctx, in.UserID) if err != nil { h.logger.WarnContext(ctx, "session not found, using empty session", "user_id", in.UserID) session = entity.Session{ UserID: in.UserID, ChatID: in.ChatID, Data: make(map[string]any), UpdatedAt: time.Now(), } } route, err := h.router.Route(ctx, msg) if err != nil { h.logger.ErrorContext(ctx, "routing failed", "error", err, "user_id", in.UserID) _ = h.gateway.SendText(ctx, in.ChatID, "Sorry, I couldn't process your message. Please try again.") return fmt.Errorf("handle text message: route: %w", err) } session.History = append(session.History, msg) if len(session.History) > 20 { session.History = session.History[len(session.History)-20:] } req := entity.WorkflowRequest{ RequestID: uuid.New().String(), ChatID: in.ChatID, UserID: in.UserID, Username: in.Username, MessageText: in.Text, Intent: entity.Intent{ Name: route.IntentName, }, Session: session, Timestamp: in.Timestamp, Metadata: map[string]any{"route_target_type": string(route.Target.Type)}, } _ = h.gateway.SendTyping(ctx, in.ChatID) resp, err := h.dispatcher.Dispatch(ctx, req) if err != nil { h.logger.ErrorContext(ctx, "dispatch failed", "error", err, "request_id", req.RequestID) _ = h.gateway.SendText(ctx, in.ChatID, "Sorry, the service is temporarily unavailable. Please try again later.") return fmt.Errorf("handle text message: dispatch: %w", err) } if resp.ReplyText != "" { if err := h.gateway.SendText(ctx, in.ChatID, resp.ReplyText); err != nil { return fmt.Errorf("handle text message: send reply: %w", err) } } session.CurrentWorkflow = route.Target.WorkflowID session.UpdatedAt = time.Now() if err := h.sessions.Set(ctx, session); err != nil { h.logger.WarnContext(ctx, "failed to persist session", "error", err, "user_id", in.UserID) } return nil }