package admin import ( "context" "encoding/json" "errors" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/yuxingu/digital-psychology/apps/api/internal/repository" ) // AskSessionDetail is AskSessionView plus messages (transcript). type AskSessionDetail struct { repository.AskSessionView Messages []repository.AskMessageView `json:"messages"` } var ErrAskThreadNotFound = errString("ask thread not found") // ListAskSessions lists AskSessionView rows. func (s *Service) ListAskSessions(ctx context.Context, userID *uuid.UUID, limit, offset int) ([]repository.AskSessionView, error) { items, err := s.Repo.ListAskSessions(ctx, userID, limit, offset) if err != nil { return nil, err } if items == nil { items = []repository.AskSessionView{} } return items, nil } // GetAskSessionMeta loads thread meta without message bodies. func (s *Service) GetAskSessionMeta(ctx context.Context, threadID uuid.UUID) (*repository.AskSessionView, error) { view, err := s.Repo.GetAskSession(ctx, threadID) if errors.Is(err, pgx.ErrNoRows) { return nil, ErrAskThreadNotFound } if err != nil { return nil, err } return view, nil } // GetAskSessionTranscript loads message bodies and audits access. func (s *Service) GetAskSessionTranscript(ctx context.Context, adminID, threadID uuid.UUID) (*AskSessionDetail, error) { view, err := s.Repo.GetAskSession(ctx, threadID) if errors.Is(err, pgx.ErrNoRows) { return nil, ErrAskThreadNotFound } if err != nil { return nil, err } msgs, err := s.Repo.ListAskMessagesForAdmin(ctx, threadID) if err != nil { return nil, err } if msgs == nil { msgs = []repository.AskMessageView{} } meta, _ := json.Marshal(map[string]any{ "message_count": len(msgs), "user_id": view.UserID.String(), }) _ = s.Repo.InsertAudit(ctx, adminID, "ask.transcript.read", "ask_thread", threadID.String(), meta) return &AskSessionDetail{AskSessionView: *view, Messages: msgs}, nil }