package message

import (
	"context"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/identity"
)

func (txs TxStore) ListAgentUnreadMessageThreads(ctx context.Context, workspaceID string, memberID string) ([]AgentUnreadThread, error) {
	trimmedWorkspaceID := strings.TrimSpace(workspaceID)
	if trimmedWorkspaceID == "" {
		return nil, fmt.Errorf("workspace id is required")
	}
	trimmedMemberID := strings.TrimSpace(memberID)
	if trimmedMemberID == "" {
		return nil, fmt.Errorf("member id is required")
	}

	ownerQuoteCutoff := OwnerQuoteReadFloor()

	messageQuery, messageArgs, err := BuildAgentUnreadThreadsQuery(trimmedWorkspaceID, trimmedMemberID, ownerQuoteCutoff)
	if err != nil {
		return nil, err
	}
	messageThreads, err := LoadAgentUnreadThreadsByQuery(ctx, txs.tx, messageQuery, messageArgs...)
	if err != nil {
		return nil, err
	}
	threads := MergeAgentUnreadThreads(messageThreads)
	if err := attachPublicNamesToAgentUnreadThreads(ctx, txs.tx, trimmedWorkspaceID, threads); err != nil {
		return nil, err
	}
	return threads, nil
}

func attachPublicNamesToAgentUnreadThreads(ctx context.Context, queryer identity.MemberIdentityQueryer, workspaceID string, threads []AgentUnreadThread) error {
	memberIDs := make([]string, 0, len(threads)*2)
	for _, thread := range threads {
		if thread.ChannelType == "dm" {
			memberIDs = append(memberIDs, thread.ChannelName)
		}
		if thread.ParentChannelType == "dm" {
			memberIDs = append(memberIDs, thread.ParentChannelName)
		}
	}
	if len(memberIDs) == 0 {
		return nil
	}
	publicNames, err := identity.LoadPublicMemberNamesByMemberID(ctx, queryer, workspaceID, memberIDs)
	if err != nil {
		return err
	}
	for i := range threads {
		if threads[i].ChannelType == "dm" {
			threads[i].ChannelName = identity.PublicMemberNameForMemberID(threads[i].ChannelName, publicNames)
		}
		if threads[i].ParentChannelType == "dm" {
			threads[i].ParentChannelName = identity.PublicMemberNameForMemberID(threads[i].ParentChannelName, publicNames)
		}
	}
	return nil
}

func LoadAgentUnreadThreadsByQuery(ctx context.Context, queryer coredb.Queryer, query string, args ...any) ([]AgentUnreadThread, error) {
	rows, err := queryer.Query(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("query unread threads: %w", err)
	}
	defer rows.Close()

	threads := make([]AgentUnreadThread, 0)
	for rows.Next() {
		var thread AgentUnreadThread
		var unreadCount int64
		if err := rows.Scan(&thread.ThreadID, &thread.ChannelType, &thread.ChannelName, &thread.ParentChannelType, &thread.ParentChannelName, &thread.LastReadSeq, &unreadCount); err != nil {
			return nil, fmt.Errorf("scan unread thread: %w", err)
		}
		if unreadCount < 0 {
			return nil, fmt.Errorf("invalid unread count")
		}
		thread.UnreadCount = int(unreadCount)
		threads = append(threads, thread)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate unread threads: %w", err)
	}
	return threads, nil
}
