package app

import (
	"context"

	"github.com/tidbcloud/AgentTeam/internal/store/message"
)

const (
	defaultChannelAttachmentsLimit = 30
	maxChannelAttachmentsLimit     = 100
)

// ListChannelAttachmentsForUser serves the channel attachments list from the
// channel_attachment_projection table (single ordered query). All viewers go
// through the projection; public-visibility authority is checked via an EXISTS
// on scope_memberships. The legacy batched 14-JOIN candidate path is retired.
func (store *Store) ListChannelAttachmentsForUser(ctx context.Context, userID string, workspaceID string, channelID string, options message.ChannelAttachmentListOptions) (message.ChannelAttachmentPage, error) {
	membership, target, err := store.resolveAuthorizedHumanMessageTarget(ctx, userID, workspaceID, channelID, channelReadAction, dmReadAction, threadReadAction)
	if err != nil {
		return message.ChannelAttachmentPage{}, err
	}
	if target.ReplyThread != nil || target.ThreadType != "channel" {
		return message.ChannelAttachmentPage{}, badRequest("resources are only supported for channels")
	}
	options = normalizeChannelAttachmentListOptions(options)
	return store.messageStore().ListChannelAttachmentsFromProjection(ctx, message.ChannelAttachmentProjectionListRequest{
		WorkspaceID:    workspaceID,
		ViewerMemberID: membership.Member.ID,
		ChannelID:      channelID,
		IncludeThreads: options.IncludeThreads,
		Kind:           options.Kind,
		Query:          options.Query,
		FromMemberID:   options.FromMemberID,
		DateFrom:       options.DateFrom,
		DateTo:         options.DateTo,
		Cursor:         options.Cursor,
		Limit:          options.Limit,
	})
}

// ListThreadAttachmentsForUser lists attachments from messages in one reply
// thread only, served from the projection scoped to that thread. Sub-thread
// recursion is disabled regardless of the caller's IncludeThreads.
func (store *Store) ListThreadAttachmentsForUser(ctx context.Context, userID string, workspaceID string, threadChannelID string, options message.ChannelAttachmentListOptions) (message.ChannelAttachmentPage, error) {
	membership, target, err := store.resolveAuthorizedHumanMessageTarget(ctx, userID, workspaceID, threadChannelID, channelReadAction, dmReadAction, threadReadAction)
	if err != nil {
		return message.ChannelAttachmentPage{}, err
	}
	if target.ReplyThread == nil {
		return message.ChannelAttachmentPage{}, badRequest("attachments are only supported for reply threads")
	}
	options = normalizeChannelAttachmentListOptions(options)
	return store.messageStore().ListChannelAttachmentsFromProjection(ctx, message.ChannelAttachmentProjectionListRequest{
		WorkspaceID:    workspaceID,
		ViewerMemberID: membership.Member.ID,
		ThreadScopeID:  threadChannelID,
		Kind:           options.Kind,
		Query:          options.Query,
		FromMemberID:   options.FromMemberID,
		DateFrom:       options.DateFrom,
		DateTo:         options.DateTo,
		Cursor:         options.Cursor,
		Limit:          options.Limit,
	})
}

func normalizeChannelAttachmentListOptions(options message.ChannelAttachmentListOptions) message.ChannelAttachmentListOptions {
	options.Kind = message.NormalizeChannelAttachmentKind(options.Kind)
	if options.Limit <= 0 {
		options.Limit = defaultChannelAttachmentsLimit
	}
	if options.Limit > maxChannelAttachmentsLimit {
		options.Limit = maxChannelAttachmentsLimit
	}
	return options
}
