package memory

import (
	"context"
	"strings"
	"time"

	memorystore "github.com/tidbcloud/AgentTeam/internal/store/resource/memory"
)

// AgentAssetAccessEvent is the service DTO for daemon asset-refresh events.
// It mirrors the public event contract carried by agent:assets:access-changed.
type AgentAssetAccessEvent struct {
	EventID     string
	WorkspaceID string
	AgentIDs    []string
	AssetTypes  []string
	Version     int64
	OccurredAt  time.Time
	Source      string

	Attempts    int
	MaxAttempts int
}

type AgentAssetAccessEventLeaseOptions struct {
	LeaseOwner    string
	LeaseDuration time.Duration
	Limit         int
	WorkspaceIDs  []string
	Now           time.Time
}

type AgentAssetAccessEventFailure struct {
	EventID       string
	LeaseOwner    string
	LastError     string
	NextAttemptAt time.Time
	Now           time.Time
}

func (s *MemoryService) LeaseAgentAssetAccessEvents(ctx context.Context, opts AgentAssetAccessEventLeaseOptions) ([]AgentAssetAccessEvent, error) {
	if s.store == nil {
		return nil, invalidArgument("memory service is not configured")
	}
	now := opts.Now
	if now.IsZero() {
		now = s.now()
	}
	rows, err := s.store.LeaseDueAgentAssetAccessChanges(ctx, now, opts.LeaseOwner, now.Add(opts.LeaseDuration), opts.Limit, opts.WorkspaceIDs)
	if err != nil {
		return nil, err
	}
	out := make([]AgentAssetAccessEvent, 0, len(rows))
	for _, row := range rows {
		out = append(out, agentAssetAccessEventFromStore(row))
	}
	return out, nil
}

func (s *MemoryService) MarkAgentAssetAccessEventDelivered(ctx context.Context, eventID, leaseOwner string, deliveredAt time.Time) (bool, error) {
	if s.store == nil {
		return false, invalidArgument("memory service is not configured")
	}
	if deliveredAt.IsZero() {
		deliveredAt = s.now()
	}
	return s.store.MarkAgentAssetAccessChangeDelivered(ctx, eventID, leaseOwner, deliveredAt)
}

func (s *MemoryService) MarkAgentAssetAccessEventFailed(ctx context.Context, failure AgentAssetAccessEventFailure) (memorystore.AgentAssetAccessAttemptResult, error) {
	if s.store == nil {
		return memorystore.AgentAssetAccessAttemptResult{}, invalidArgument("memory service is not configured")
	}
	eventID := strings.TrimSpace(failure.EventID)
	if eventID == "" {
		return memorystore.AgentAssetAccessAttemptResult{}, invalidArgument("event id is required")
	}
	now := failure.Now
	if now.IsZero() {
		now = s.now()
	}
	row, err := s.store.GetAgentAssetAccessChange(ctx, eventID)
	if err != nil {
		return memorystore.AgentAssetAccessAttemptResult{}, err
	}
	return s.store.MarkAgentAssetAccessChangeAttemptFailed(ctx, row, failure.LeaseOwner, failure.LastError, failure.NextAttemptAt, now)
}

func agentAssetAccessEventFromStore(row memorystore.AgentAssetAccessChangeOutbox) AgentAssetAccessEvent {
	source := strings.TrimSpace(row.Source)
	if source == "" {
		source = memorystore.AgentAssetAccessSourceOutbox
	}
	return AgentAssetAccessEvent{
		EventID:     strings.TrimSpace(row.ID),
		WorkspaceID: strings.TrimSpace(row.WorkspaceID),
		AgentIDs:    []string{strings.TrimSpace(row.AgentID)},
		AssetTypes:  []string{strings.TrimSpace(row.AssetType)},
		Version:     row.Version,
		OccurredAt:  row.OccurredAt,
		Source:      source,
		Attempts:    row.Attempts,
		MaxAttempts: row.MaxAttempts,
	}
}
