package server

import (
	"context"
	"errors"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/store/serviceaccount"
	"github.com/tidbcloud/AgentTeam/internal/unread"
)

type serviceAccountUnreadRuntime interface {
	ApplyScopeInvalidatedWithDeltas(event unread.ScopeInvalidated) ([]unread.UnreadDelta, error)
}

type serviceAccountUnreadDeltaSink interface {
	EmitUnreadUpdated(workspaceID string, delta unread.UnreadDelta)
}

type serviceAccountDeletionLiveSink interface {
	EmitServiceAccountDeleted(workspaceID string, accountID string, principalID string, scopeID string)
}

type serviceAccountUnreadRuntimeBridge struct {
	runtime   serviceAccountUnreadRuntime
	deltaSink serviceAccountUnreadDeltaSink
}

func newServiceAccountUnreadRuntimeBridge(runtime serviceAccountUnreadRuntime, deltaSink serviceAccountUnreadDeltaSink) *serviceAccountUnreadRuntimeBridge {
	if runtime == nil {
		return nil
	}
	return &serviceAccountUnreadRuntimeBridge{runtime: runtime, deltaSink: deltaSink}
}

func (bridge *serviceAccountUnreadRuntimeBridge) LocalAccountsDeleted(_ context.Context, accounts []serviceaccount.Account) error {
	if bridge == nil || bridge.runtime == nil {
		return nil
	}
	var result error
	for _, account := range accounts {
		workspaceID := strings.TrimSpace(account.WorkspaceID)
		scopeID := strings.TrimSpace(account.MessageScopeID)
		if workspaceID == "" || scopeID == "" {
			continue
		}
		if sink, ok := bridge.deltaSink.(serviceAccountDeletionLiveSink); ok {
			sink.EmitServiceAccountDeleted(
				workspaceID,
				strings.TrimSpace(account.ID),
				strings.TrimSpace(account.PrincipalID),
				scopeID,
			)
		}
		deltas, err := bridge.runtime.ApplyScopeInvalidatedWithDeltas(unread.ScopeInvalidated{
			WorkspaceID: workspaceID,
			ScopeID:     scopeID,
			Reason:      "service_account_delete",
			Permanent:   true,
		})
		if err != nil {
			result = errors.Join(result, fmt.Errorf("invalidate deleted service account scope %s: %w", scopeID, err))
			continue
		}
		if bridge.deltaSink == nil {
			continue
		}
		for _, delta := range deltas {
			bridge.deltaSink.EmitUnreadUpdated(workspaceID, delta)
		}
	}
	return result
}
