package message

import (
	"context"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/core/domain"
	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
)

func (store *Store) SupportsMessageSearch(ctx context.Context) bool {
	supported := false
	_ = coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		supported = store.InTx(tx).SupportsMessageSearch(ctx)
		return nil
	})
	return supported
}

func (store *Store) SupportsWorkspaceMessageSearch(ctx context.Context, workspaceID string) bool {
	supported := false
	_ = coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		supported = store.InTx(tx).SupportsWorkspaceMessageSearch(ctx, workspaceID)
		return nil
	})
	return supported
}

func (store *Store) SearchMessagesForUser(ctx context.Context, userID string, workspaceID string, query string, scopeID string, options MessageSearchOptions) (MessageSearchResult, error) {
	var result MessageSearchResult
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).SearchMessagesForUser(ctx, userID, workspaceID, query, scopeID, options)
		return err
	})
	if err != nil {
		return MessageSearchResult{}, err
	}
	return result, nil
}

func (store *Store) ListAgentUnreadMessageThreads(ctx context.Context, workspaceID string, memberID string) ([]AgentUnreadThread, error) {
	var result []AgentUnreadThread
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ListAgentUnreadMessageThreads(ctx, workspaceID, memberID)
		return err
	})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (store *Store) OpenReplyThreadForUser(ctx context.Context, userID string, workspaceID string, channelID string, parentMessageID string) (ReplyThreadSummary, error) {
	var result ReplyThreadSummary
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).OpenReplyThreadForUser(ctx, userID, workspaceID, channelID, parentMessageID)
		return err
	})
	if err != nil {
		return ReplyThreadSummary{}, err
	}
	return result, nil
}

func (store *Store) ListReplyThreadSummariesForUser(ctx context.Context, userID string, workspaceID string, channelID string) (map[string]ReplyThreadSummary, error) {
	return store.ListReplyThreadSummariesForUserWithLimit(ctx, userID, workspaceID, channelID, 0)
}

func (store *Store) ListReplyThreadSummariesForUserWithLimit(ctx context.Context, userID string, workspaceID string, channelID string, limit int) (map[string]ReplyThreadSummary, error) {
	var result map[string]ReplyThreadSummary
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ListReplyThreadSummariesForUserWithLimit(ctx, userID, workspaceID, channelID, limit)
		return err
	})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (store *Store) ListSubscribedThreadsForUser(ctx context.Context, userID string, workspaceID string) ([]SubscribedThread, error) {
	return store.ListSubscribedThreadsForUserWithLimit(ctx, userID, workspaceID, 0)
}

func (store *Store) ListSubscribedThreadInboxPageForUser(ctx context.Context, userID string, workspaceID string, limit int, cursor ThreadInboxCursor) (ThreadInboxPage, error) {
	var result ThreadInboxPage
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ListSubscribedThreadInboxPageForUser(ctx, userID, workspaceID, limit, cursor)
		return err
	})
	if err != nil {
		return ThreadInboxPage{}, err
	}
	return result, nil
}

func (store *Store) CountSubscribedThreadsForUser(ctx context.Context, userID string, workspaceID string) (ThreadInboxCount, error) {
	var result ThreadInboxCount
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).CountSubscribedThreadsForUser(ctx, userID, workspaceID)
		return err
	})
	if err != nil {
		return ThreadInboxCount{}, err
	}
	return result, nil
}

func (store *Store) ListSubscribedThreadsForUserWithLimit(ctx context.Context, userID string, workspaceID string, limit int) ([]SubscribedThread, error) {
	var result []SubscribedThread
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).ListSubscribedThreadsForUserWithLimit(ctx, userID, workspaceID, limit)
		return err
	})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (store *Store) GetReplyThreadForUser(ctx context.Context, userID string, workspaceID string, threadChannelID string) (SubscribedThread, error) {
	var result SubscribedThread
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).GetReplyThreadForUser(ctx, userID, workspaceID, threadChannelID)
		return err
	})
	if err != nil {
		return SubscribedThread{}, err
	}
	return result, nil
}

func (store *Store) GetThreadMembershipForUser(ctx context.Context, userID string, workspaceID string, threadChannelID string) (ThreadMembership, error) {
	var result ThreadMembership
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).GetThreadMembershipForUser(ctx, userID, workspaceID, threadChannelID)
		return err
	})
	if err != nil {
		return ThreadMembership{}, err
	}
	return result, nil
}

func (store *Store) UnsubscribeThreadForUser(ctx context.Context, userID string, workspaceID string, threadChannelID string) error {
	return coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		return store.InTx(tx).UnsubscribeThreadForUser(ctx, userID, workspaceID, threadChannelID)
	})
}

func (store *Store) SubscribeThreadForUser(ctx context.Context, userID string, workspaceID string, threadChannelID string) error {
	return coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		return store.InTx(tx).SubscribeThreadForUser(ctx, userID, workspaceID, threadChannelID)
	})
}

func (store *Store) SetThreadSubscriptionStateForUser(ctx context.Context, userID string, workspaceID string, threadChannelID string, state string) error {
	return coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		return store.InTx(tx).SetThreadSubscriptionStateForUser(ctx, userID, workspaceID, threadChannelID, state)
	})
}

func (store *Store) SyncReplyThreadSubscriptions(ctx context.Context, authorMemberID string, authorType domain.MemberType, threadChannelID string, parentMessageID string, mentionedMemberIDs []string, agentMentionMemberIDs []string, currentMessageSeq int64, currentMessageGlobalSeq int64, subscribedAt time.Time) error {
	return coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		return store.InTx(tx).SyncReplyThreadSubscriptions(ctx, authorMemberID, authorType, threadChannelID, parentMessageID, mentionedMemberIDs, agentMentionMemberIDs, currentMessageSeq, currentMessageGlobalSeq, subscribedAt)
	})
}

func (store *Store) EnsureReplyThreadParentAuthorParticipant(ctx context.Context, threadChannelID string, parentMessageID string, participatedAt time.Time) error {
	return coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		return store.InTx(tx).EnsureReplyThreadParentAuthorParticipant(ctx, threadChannelID, parentMessageID, participatedAt)
	})
}

func (store *Store) GetMessageDeliveryDiagnosticsForUser(ctx context.Context, userID string, workspaceID string, messageID string) (MessageDeliveryDiagnostics, error) {
	var result MessageDeliveryDiagnostics
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).GetMessageDeliveryDiagnosticsForUser(ctx, userID, workspaceID, messageID)
		return err
	})
	if err != nil {
		return MessageDeliveryDiagnostics{}, err
	}
	return result, nil
}

func (store *Store) ReadThreadHistoryRecords(ctx context.Context, workspaceID string, threadID string, limit int, before *int64, after *int64) ([]model.ThreadMessageRecord, bool, error) {
	var result []model.ThreadMessageRecord
	var hasMore bool
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, hasMore, err = store.InTx(tx).ReadThreadHistoryRecords(ctx, workspaceID, threadID, limit, before, after)
		return err
	})
	if err != nil {
		return nil, false, err
	}
	return result, hasMore, nil
}

func (store *Store) LoadOwnerPrivateContextVisibility(ctx context.Context, workspaceID string, agentMemberID string, threadID string) (OwnerPrivateContextVisibility, error) {
	var result OwnerPrivateContextVisibility
	err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		var err error
		result, err = store.InTx(tx).LoadOwnerPrivateContextVisibility(ctx, workspaceID, agentMemberID, threadID)
		return err
	})
	if err != nil {
		return OwnerPrivateContextVisibility{}, err
	}
	return result, nil
}
