package activity

import (
	"context"
	"strings"
	"time"

	activitystore "github.com/tidbcloud/AgentTeam/internal/store/resource/activity"
)

const (
	ActivityActorTypeUser   = "user"
	ActivityActorTypeSystem = "system"

	ActivitySourceControl = activitystore.SourceControl
)

// ResourceActivityEventInput is the service-layer mutation input used to
// normalize and persist one resource-domain activity event. It is neither the
// resource/activity store row nor a public API request DTO.
type ResourceActivityEventInput struct {
	WorkspaceID   string
	AssetType     string
	AssetID       string
	RepoFullName  string
	EventType     string
	ActorType     string
	ActorID       string
	ActorName     string
	SummaryKey    string
	Details       any
	Display       ResourceActivityDisplay
	TargetKind    string
	TargetID      string
	TargetURL     string
	Source        string
	SourceEventID string
	OccurredAt    time.Time
}

// WriteResourceActivityEvent normalizes and upserts one resource-domain event
// through the activity persistence owner. A nil store makes the optional
// activity side effect a no-op.
func WriteResourceActivityEvent(ctx context.Context, store *activitystore.Store, input ResourceActivityEventInput) error {
	if store == nil {
		return nil
	}
	occurredAt := input.OccurredAt
	if occurredAt.IsZero() {
		occurredAt = time.Now().UTC()
	}
	actorType := strings.TrimSpace(input.ActorType)
	if actorType == "" {
		if strings.TrimSpace(input.ActorID) == "" {
			actorType = ActivityActorTypeSystem
		} else {
			actorType = ActivityActorTypeUser
		}
	}
	source := strings.TrimSpace(input.Source)
	if source == "" {
		source = ActivitySourceControl
	}
	summaryKey := strings.TrimSpace(input.SummaryKey)
	if summaryKey == "" {
		summaryKey = defaultActivitySummaryKey(input.AssetType, input.EventType)
	}
	actorName := strings.TrimSpace(input.ActorName)
	detailsJSON, err := marshalActivityDetails(input.Details, input.Display)
	if err != nil {
		return err
	}
	var sourceEventID *string
	if trimmed := strings.TrimSpace(input.SourceEventID); trimmed != "" {
		sourceEventID = &trimmed
	}
	_, err = store.UpsertEvent(ctx, activitystore.ResourceActivityEvent{
		WorkspaceID:   strings.TrimSpace(input.WorkspaceID),
		AssetType:     strings.TrimSpace(input.AssetType),
		AssetID:       strings.TrimSpace(input.AssetID),
		RepoFullName:  strings.TrimSpace(input.RepoFullName),
		EventType:     strings.TrimSpace(input.EventType),
		ActorType:     actorType,
		ActorID:       strings.TrimSpace(input.ActorID),
		ActorName:     actorName,
		SummaryKey:    summaryKey,
		DetailsJSON:   detailsJSON,
		TargetKind:    strings.TrimSpace(input.TargetKind),
		TargetID:      strings.TrimSpace(input.TargetID),
		TargetURL:     strings.TrimSpace(input.TargetURL),
		Source:        source,
		SourceEventID: sourceEventID,
		OccurredAt:    occurredAt,
		CreatedAt:     occurredAt,
	})
	return err
}

func marshalActivityDetails(details any, display ResourceActivityDisplay) (string, error) {
	payload, err := normalizeActivityDetailsMap(details)
	if err != nil {
		return "", err
	}
	display = normalizeResourceActivityDisplay(display)
	if !display.empty() {
		payload[activityDetailsDisplayKey] = display
	}
	return marshalActivityDetailsMap(payload)
}

func defaultActivitySummaryKey(assetType, eventType string) string {
	eventType = strings.TrimSpace(eventType)
	if eventType == "" {
		return strings.TrimSpace(assetType)
	}
	return eventType
}
