package message

import (
	"context"
	"fmt"
	"strings"

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

type appMessageRouteContext struct {
	ChannelType       string
	ParentChannelID   string
	ParentChannelType string
	ParentMessageID   string
	TaskContext       *AppMessageTaskContext
}

func loadAppMessageRouteContexts(ctx context.Context, queryer coredb.Queryer, workspaceID string, scopeIDs []string) (map[string]appMessageRouteContext, error) {
	normalizedWorkspaceID := strings.TrimSpace(workspaceID)
	normalizedScopeIDs := normalizeNonEmptyStrings(scopeIDs)
	if queryer == nil || normalizedWorkspaceID == "" || len(normalizedScopeIDs) == 0 {
		return map[string]appMessageRouteContext{}, nil
	}

	requestedScopesCTE, requestedScopeArgs, _, err := coredb.BuildStringValuesCTE("requested_scopes", "scope_id", normalizedScopeIDs, 2)
	if err != nil {
		return nil, err
	}
	args := append([]any{normalizedWorkspaceID}, requestedScopeArgs...)
	rows, err := queryer.Query(ctx, fmt.Sprintf(`
WITH %s
SELECT
  requested_scopes.scope_id,
  s.type,
  COALESCE(parent.id, ''),
  COALESCE(parent.type, ''),
  COALESCE(s.root_message_id, ''),
  COALESCE(task_board.channel_id, ''),
  COALESCE(t.task_number, 0)
FROM requested_scopes
JOIN scopes s
  ON s.id = requested_scopes.scope_id
 AND s.workspace_id = $1
LEFT JOIN scopes parent
  ON parent.id = s.parent_scope_id
 AND parent.workspace_id = s.workspace_id
 AND s.type = 'thread'
LEFT JOIN tasks t
  ON t.task_scope_id = s.id
 AND s.type = 'task'
LEFT JOIN task_boards task_board
  ON task_board.id = t.board_id
 AND task_board.workspace_id = s.workspace_id
LEFT JOIN scopes task_channel
  ON task_channel.id = task_board.channel_id
 AND task_channel.workspace_id = s.workspace_id
 AND task_channel.type = 'channel'
 AND task_channel.status = 'active'
 AND task_channel.archived_at IS NULL
 AND t.channel_id = task_board.channel_id
`, requestedScopesCTE), args...)
	if err != nil {
		return nil, fmt.Errorf("load app message route contexts: %w", err)
	}
	defer rows.Close()

	contexts := make(map[string]appMessageRouteContext, len(normalizedScopeIDs))
	for rows.Next() {
		var scopeID string
		var scopeType string
		var parentChannelID string
		var parentChannelType string
		var parentMessageID string
		var taskChannelID string
		var taskNumber int64
		if err := rows.Scan(
			&scopeID,
			&scopeType,
			&parentChannelID,
			&parentChannelType,
			&parentMessageID,
			&taskChannelID,
			&taskNumber,
		); err != nil {
			return nil, fmt.Errorf("scan app message route context: %w", err)
		}

		normalizedScopeID := strings.TrimSpace(scopeID)
		if normalizedScopeID == "" {
			continue
		}
		routeContext := appMessageRouteContext{
			ChannelType:       strings.TrimSpace(scopeType),
			ParentChannelID:   strings.TrimSpace(parentChannelID),
			ParentChannelType: strings.TrimSpace(parentChannelType),
			ParentMessageID:   strings.TrimSpace(parentMessageID),
		}
		if routeContext.ChannelType == "task" {
			normalizedTaskChannelID := strings.TrimSpace(taskChannelID)
			if normalizedTaskChannelID != "" && taskNumber > 0 {
				routeContext.TaskContext = &AppMessageTaskContext{
					ChannelID:  normalizedTaskChannelID,
					TaskNumber: taskNumber,
				}
			}
		}
		contexts[normalizedScopeID] = routeContext
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate app message route contexts: %w", err)
	}
	return contexts, nil
}

func applyAppMessageRouteContext(appMessage *AppMessage, routeContext appMessageRouteContext) {
	if appMessage == nil {
		return
	}
	appMessage.ChannelType = routeContext.ChannelType
	appMessage.ParentChannelID = routeContext.ParentChannelID
	appMessage.ParentChannelType = routeContext.ParentChannelType
	appMessage.ParentMessageID = routeContext.ParentMessageID
	appMessage.TaskContext = routeContext.TaskContext
}

func visibleRefScopeIDs(refs []VisibleMessageRef) []string {
	scopeIDs := make([]string, 0, len(refs))
	for _, ref := range refs {
		scopeIDs = append(scopeIDs, ref.Message.ScopeID)
	}
	return scopeIDs
}
