package service import ( "errors" "narasi-ahli-be/app/database/entity" "narasi-ahli-be/app/module/chat_history/mapper" "narasi-ahli-be/app/module/chat_history/repository" "narasi-ahli-be/app/module/chat_history/request" "narasi-ahli-be/app/module/chat_history/response" usersRepository "narasi-ahli-be/app/module/users/repository" "narasi-ahli-be/utils/paginator" utilSvc "narasi-ahli-be/utils/service" "github.com/rs/zerolog" ) type chatHistoryService struct { Repo repository.ChatHistoryRepository UsersRepo usersRepository.UsersRepository Log zerolog.Logger } type ChatHistoryService interface { // Sessions GetUserSessions(authToken string, req request.ChatHistorySessionsQueryRequest) (sessions []*response.ChatHistorySessionsResponse, paging paginator.Pagination, err error) GetSession(authToken string, sessionID string) (session *response.ChatHistorySessionWithMessagesResponse, err error) CreateSession(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error) UpdateSession(authToken string, sessionID string, req request.ChatHistorySessionsUpdateRequest) (err error) DeleteSession(authToken string, sessionID string) error // Messages GetSessionMessages(authToken string, sessionID string, req request.ChatHistoryMessagesQueryRequest) (messages []*response.ChatHistoryMessagesResponse, paging paginator.Pagination, err error) CreateMessage(authToken string, req request.ChatHistoryMessagesCreateRequest) (message *response.ChatHistoryMessagesResponse, err error) UpdateMessage(authToken string, messageID uint, req request.ChatHistoryMessagesUpdateRequest) (err error) DeleteMessage(authToken string, messageID uint) error // Combined operations SaveChatHistory(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error) } func NewChatHistoryService(repo repository.ChatHistoryRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger) ChatHistoryService { return &chatHistoryService{ Repo: repo, UsersRepo: usersRepo, Log: log, } } // Sessions methods func (_i *chatHistoryService) GetUserSessions(authToken string, req request.ChatHistorySessionsQueryRequest) (sessions []*response.ChatHistorySessionsResponse, paging paginator.Pagination, err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) // Set user ID from auth token req.UserID = &userInfo.ID results, paging, err := _i.Repo.GetUserSessions(userInfo.ID, req) if err != nil { return } for _, result := range results { sessions = append(sessions, mapper.ChatHistorySessionsResponseMapper(result)) } return } func (_i *chatHistoryService) GetSession(authToken string, sessionID string) (session *response.ChatHistorySessionWithMessagesResponse, err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) // Verify session belongs to user sessionEntity, err := _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID) if err != nil { return nil, err } // Get messages for this session messagesReq := request.ChatHistoryMessagesQueryRequest{ SessionID: sessionID, Pagination: &paginator.Pagination{ Limit: 1000, // Get all messages for now }, } messages, _, err := _i.Repo.GetSessionMessages(sessionID, messagesReq) if err != nil { return nil, err } return mapper.ChatHistorySessionWithMessagesResponseMapper(sessionEntity, messages), nil } func (_i *chatHistoryService) CreateSession(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) // Set user ID from auth token req.UserID = userInfo.ID entity := req.ToEntity() result, err := _i.Repo.CreateSession(entity) if err != nil { return nil, err } return mapper.ChatHistorySessionsResponseMapper(result), nil } func (_i *chatHistoryService) UpdateSession(authToken string, sessionID string, req request.ChatHistorySessionsUpdateRequest) (err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) _i.Log.Info().Interface("data", req).Msg("Updating chat history session") // Check if session exists and belongs to user existing, err := _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID) if err != nil { return err } if existing == nil { return errors.New("chat history session not found") } entity := req.ToEntity() return _i.Repo.UpdateSession(sessionID, entity) } func (_i *chatHistoryService) DeleteSession(authToken string, sessionID string) error { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) _i.Log.Info().Uint("userId", userInfo.ID).Str("sessionId", sessionID).Msg("Deleting chat history session") // Check if session exists and belongs to user existing, err := _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID) if err != nil { return err } if existing == nil { return errors.New("chat history session not found") } return _i.Repo.DeleteSession(sessionID) } // Messages methods func (_i *chatHistoryService) GetSessionMessages(authToken string, sessionID string, req request.ChatHistoryMessagesQueryRequest) (messages []*response.ChatHistoryMessagesResponse, paging paginator.Pagination, err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) // Verify session belongs to user _, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID) if err != nil { return nil, paginator.Pagination{}, err } results, paging, err := _i.Repo.GetSessionMessages(sessionID, req) if err != nil { return } for _, result := range results { messages = append(messages, mapper.ChatHistoryMessagesResponseMapper(result)) } return } func (_i *chatHistoryService) CreateMessage(authToken string, req request.ChatHistoryMessagesCreateRequest) (message *response.ChatHistoryMessagesResponse, err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) _i.Log.Info().Interface("data", req).Msg("Creating chat history message") // Verify session belongs to user _, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, req.SessionID) if err != nil { return nil, err } entity := req.ToEntity() result, err := _i.Repo.CreateMessage(entity) if err != nil { return nil, err } // Increment message count in session err = _i.Repo.IncrementMessageCount(req.SessionID) if err != nil { _i.Log.Error().Err(err).Msg("Failed to increment message count") } return mapper.ChatHistoryMessagesResponseMapper(result), nil } func (_i *chatHistoryService) UpdateMessage(authToken string, messageID uint, req request.ChatHistoryMessagesUpdateRequest) (err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) // Get message to verify it belongs to user's session messages, _, err := _i.Repo.GetSessionMessages("", request.ChatHistoryMessagesQueryRequest{}) if err != nil { return err } // Find the specific message var targetMessage *entity.ChatMessagesNew for _, msg := range messages { if msg.ID == messageID { targetMessage = msg break } } if targetMessage == nil { return errors.New("message not found") } // Verify session belongs to user _, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, targetMessage.SessionID) if err != nil { return err } entity := req.ToEntity() return _i.Repo.UpdateMessage(messageID, entity) } func (_i *chatHistoryService) DeleteMessage(authToken string, messageID uint) error { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) // Get message to verify it belongs to user's session messages, _, err := _i.Repo.GetSessionMessages("", request.ChatHistoryMessagesQueryRequest{}) if err != nil { return err } // Find the specific message var targetMessage *entity.ChatMessagesNew for _, msg := range messages { if msg.ID == messageID { targetMessage = msg break } } if targetMessage == nil { return errors.New("message not found") } // Verify session belongs to user _, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, targetMessage.SessionID) if err != nil { return err } return _i.Repo.DeleteMessage(messageID) } // Combined operations func (_i *chatHistoryService) SaveChatHistory(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error) { userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) _i.Log.Info().Interface("data", req).Msg("Saving chat history") // Set user ID from auth token req.UserID = userInfo.ID // Check if session already exists existingSession, err := _i.Repo.FindSessionBySessionID(req.SessionID) if err == nil && existingSession != nil { // Update existing session updateReq := request.ChatHistorySessionsUpdateRequest{ Title: req.Title, } err = _i.UpdateSession(authToken, req.SessionID, updateReq) if err != nil { return nil, err } // Delete existing messages err = _i.Repo.DeleteMessagesBySessionID(req.SessionID) if err != nil { _i.Log.Error().Err(err).Msg("Failed to delete existing messages") } } else { // Create new session entity := req.ToEntity() _, err = _i.Repo.CreateSession(entity) if err != nil { return nil, err } } // Save messages if provided if len(req.Messages) > 0 { for _, msgReq := range req.Messages { messageEntity := &entity.ChatMessagesNew{ SessionID: req.SessionID, MessageType: msgReq.Type, Content: msgReq.Content, } _, err = _i.Repo.CreateMessage(messageEntity) if err != nil { _i.Log.Error().Err(err).Msg("Failed to create message") } } // Update message count err = _i.Repo.UpdateSession(req.SessionID, &entity.ChatSessions{ MessageCount: len(req.Messages), }) if err != nil { _i.Log.Error().Err(err).Msg("Failed to update message count") } } // Return the session result, err := _i.Repo.FindSessionBySessionID(req.SessionID) if err != nil { return nil, err } return mapper.ChatHistorySessionsResponseMapper(result), nil }