package app

import (
	"context"
	"fmt"
	"strings"

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

func attachAppMessageDeliverySummaryPreviewsForTarget(ctx context.Context, queryer coredb.Queryer, target message.ThreadAccess, messages []message.AppMessage) error {
	if len(messages) == 0 {
		return nil
	}

	currentScopeAgents, err := loadAppMessageDeliverySummaryScopeAgents(ctx, queryer, target)
	if err != nil {
		return err
	}
	channelType := appMessageDeliverySummaryChannelType(target)
	for i := range messages {
		durableRecipients := message.DeriveMessageDiagnosticsRecipientsFromScope(message.MessageDeliveryDiagnosticsMessage{
			ID:             strings.TrimSpace(messages[i].ID),
			ChannelType:    channelType,
			AuthorMemberID: strings.TrimSpace(messages[i].AuthorMemberID()),
			AuthorUserID:   appMessageAuthorUserID(messages[i]),
			AuthorType:     strings.TrimSpace(messages[i].AuthorActorType()),
			MessageType:    strings.TrimSpace(messages[i].MessageType),
			Content:        messages[i].Content,
		}, currentScopeAgents)
		previewState := buildAppMessageDeliverySummaryPreviewState(
			messages[i],
			channelType,
			currentScopeAgents,
			durableRecipients,
		)
		messages[i].DeliverySummaryPreview = previewState.Preview
		messages[i].DeliveryDiagnosticsEnabled = previewState.DiagnosticsEnabled
	}
	return nil
}

func attachAppMessageDeliverySummaryPreviewForTarget(ctx context.Context, queryer coredb.Queryer, target message.ThreadAccess, appMessage *message.AppMessage) error {
	if appMessage == nil {
		return nil
	}

	messages := []message.AppMessage{*appMessage}
	if err := attachAppMessageDeliverySummaryPreviewsForTarget(ctx, queryer, target, messages); err != nil {
		return err
	}
	*appMessage = messages[0]
	return nil
}

func (store *Store) AttachAppMessageDeliverySummaryPreviewForTarget(ctx context.Context, target message.ThreadAccess, appMessage *message.AppMessage) error {
	return attachAppMessageDeliverySummaryPreviewForTarget(ctx, store.db, target, appMessage)
}

func appMessageDeliverySummaryChannelType(target message.ThreadAccess) string {
	if target.ReplyThread != nil {
		return "thread"
	}
	if target.ThreadType == domain.ThreadTypeDM {
		return "dm"
	}
	return "channel"
}

func loadAppMessageDeliverySummaryScopeAgents(ctx context.Context, queryer coredb.Queryer, target message.ThreadAccess) ([]message.DiagnosticsAgentState, error) {
	scopeID := message.ScopeIDForThreadAccess(target)
	if strings.TrimSpace(scopeID) == "" {
		return nil, nil
	}
	return loadAppMessageDeliverySummaryScopeAgentsByScope(ctx, queryer, scopeID)
}

func loadAppMessageDeliverySummaryScopeAgentsByScope(ctx context.Context, queryer coredb.Queryer, scopeID string) ([]message.DiagnosticsAgentState, error) {
	rows, err := queryer.Query(ctx, `
SELECT
    a.id,
    a.name,
    a.member_id,
    a.machine_id,
    COALESCE(mac.name, ''),
    mac.created_by_user_id,
    'inactive',
    'offline',
    '',
    CASE WHEN sns.state = 'auto-wake' THEN 1 ELSE 0 END AS auto_wake_enabled,
    COALESCE(sns.state, '') AS subscription_state,
    FALSE AS machine_online
FROM scope_memberships sm
JOIN scopes sc ON sc.id = sm.scope_id
JOIN agents a
  ON a.workspace_id = sc.workspace_id
 AND a.member_id = sm.member_id
 AND a.status <> 'archived'
JOIN machines mac
  ON mac.workspace_id = a.workspace_id
 AND mac.id = a.machine_id
 AND mac.status = 'active'
LEFT JOIN scope_notification_settings sns
  ON sns.scope_id = sm.scope_id
 AND sns.member_id = sm.member_id
WHERE sm.scope_id = $1
  AND sm.removed_at IS NULL
ORDER BY a.name ASC, a.member_id ASC, a.id ASC
`, strings.TrimSpace(scopeID))
	if err != nil {
		return nil, fmt.Errorf("load app message delivery summary scope agents: %w", err)
	}
	defer rows.Close()

	agents := make([]message.DiagnosticsAgentState, 0)
	for rows.Next() {
		var agent message.DiagnosticsAgentState
		if err := rows.Scan(
			&agent.AgentID,
			&agent.AgentName,
			&agent.MemberID,
			&agent.MachineID,
			&agent.MachineName,
			&agent.OwnerUserID,
			&agent.AgentStatus,
			&agent.AgentActivity,
			&agent.ActivityDetail,
			&agent.AutoWakeEnabled,
			&agent.SubscriptionState,
			&agent.MachineOnline,
		); err != nil {
			return nil, fmt.Errorf("scan app message delivery summary scope agent: %w", err)
		}
		agents = append(agents, agent)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate app message delivery summary scope agents: %w", err)
	}
	return agents, nil
}

type AppMessageDeliverySummaryPreviewState struct {
	Preview            *message.AppMessageDeliverySummaryPreview
	DiagnosticsEnabled *bool
}

func appMessageSummaryFromStore(appMessage message.AppMessage) message.DeliverySummaryMessage {
	return message.DeliverySummaryMessage{
		ID:             appMessage.ID,
		AuthorMemberID: appMessage.AuthorMemberID(),
		AuthorUserID:   appMessageAuthorUserID(appMessage),
		AuthorType:     appMessage.AuthorActorType(),
		MessageType:    appMessage.MessageType,
		Content:        appMessage.Content,
	}
}

func appMessageAuthorUserID(appMessage message.AppMessage) string {
	if strings.TrimSpace(appMessage.AuthorActorType()) != message.AuthorActorTypeHuman {
		return ""
	}
	return strings.TrimSpace(appMessage.AuthorPrincipalID())
}

func appMessageDeliverySummaryPreviewFromMessage(preview *message.DeliverySummaryPreview) *message.AppMessageDeliverySummaryPreview {
	if preview == nil {
		return nil
	}
	return &message.AppMessageDeliverySummaryPreview{
		TargetedAgentCount: preview.TargetedAgentCount,
		ExcludedAgentCount: preview.ExcludedAgentCount,
		ActiveNowCount:     preview.ActiveNowCount,
	}
}

func buildAppMessageDeliverySummaryPreviewState(appMessage message.AppMessage, channelType string, currentScopeAgents []message.DiagnosticsAgentState, durableRecipients []message.DiagnosticsAgentState) AppMessageDeliverySummaryPreviewState {
	state := message.BuildDeliverySummaryPreviewState(appMessageSummaryFromStore(appMessage), channelType, currentScopeAgents, durableRecipients)
	return AppMessageDeliverySummaryPreviewState{
		Preview:            appMessageDeliverySummaryPreviewFromMessage(state.Preview),
		DiagnosticsEnabled: state.DiagnosticsEnabled,
	}
}

func BuildAppMessageDeliverySummaryPreviewState(appMessage message.AppMessage, channelType string, currentScopeAgents []message.DiagnosticsAgentState, durableRecipients []message.DiagnosticsAgentState) AppMessageDeliverySummaryPreviewState {
	return buildAppMessageDeliverySummaryPreviewState(appMessage, channelType, currentScopeAgents, durableRecipients)
}

func buildAppMessageDeliverySummaryPreview(appMessage message.AppMessage, channelType string, currentScopeAgents []message.DiagnosticsAgentState, durableRecipients []message.DiagnosticsAgentState) *message.AppMessageDeliverySummaryPreview {
	return buildAppMessageDeliverySummaryPreviewState(
		appMessage,
		channelType,
		currentScopeAgents,
		durableRecipients,
	).Preview
}

func BuildAppMessageDeliverySummaryPreview(appMessage message.AppMessage, channelType string, currentScopeAgents []message.DiagnosticsAgentState, durableRecipients []message.DiagnosticsAgentState) *message.AppMessageDeliverySummaryPreview {
	return buildAppMessageDeliverySummaryPreview(appMessage, channelType, currentScopeAgents, durableRecipients)
}

func shouldSuppressAppMessageDeliverySummaryDiagnostics(channelType string, appMessage message.AppMessage, routingMode string, durableRecipients []message.DiagnosticsAgentState, ownerPrivateRelevantAgentIDs map[string]struct{}) bool {
	return message.ShouldSuppressDeliverySummaryDiagnostics(channelType, appMessageSummaryFromStore(appMessage), routingMode, durableRecipients, ownerPrivateRelevantAgentIDs)
}
