package protosocket

import (
	"context"
	"time"

	"github.com/nomadcode/nomadcode-core/internal/notification"
)

// SuccessResponse builds a response envelope correlated to a request.
func SuccessResponse(req Envelope, payload map[string]any) Envelope {
	return Envelope{
		ProtocolVersion: ProtocolVersion,
		ID:              generateID(),
		CorrelationID:   req.ID,
		Type:            "response",
		Channel:         req.Channel,
		Action:          req.Action,
		Payload:         payload,
	}
}

// ErrorResponse builds an error envelope correlated to a request.
func ErrorResponse(req Envelope, code, message string, retryable bool) Envelope {
	return Envelope{
		ProtocolVersion: ProtocolVersion,
		ID:              generateID(),
		CorrelationID:   req.ID,
		Type:            "error",
		Channel:         req.Channel,
		Action:          req.Action,
		Error: &EnvelopeError{
			Code:      code,
			Message:   message,
			Retryable: retryable,
		},
	}
}

// Broadcaster publishes an envelope to all connected clients.
type Broadcaster interface {
	BroadcastEnvelope(ctx context.Context, env Envelope) error
}

// TaskEventBroadcaster adapts notification task events into proto-socket
// task.status.changed events. It implements notification.TaskEventSink.
type TaskEventBroadcaster struct {
	broadcaster Broadcaster
}

func NewTaskEventBroadcaster(broadcaster Broadcaster) *TaskEventBroadcaster {
	return &TaskEventBroadcaster{broadcaster: broadcaster}
}

func (b *TaskEventBroadcaster) HandleTaskEvent(ctx context.Context, event notification.TaskEvent) error {
	return b.broadcaster.BroadcastEnvelope(ctx, TaskStatusChangedEnvelope(event))
}

// TaskStatusChangedEnvelope maps a notification task event onto the
// task.status.changed event envelope.
func TaskStatusChangedEnvelope(event notification.TaskEvent) Envelope {
	payload := map[string]any{
		"id":      event.TaskID,
		"type":    string(event.Type),
		"status":  event.Status,
		"title":   event.Title,
		"message": event.Message,
		"attempt": event.Attempt,
	}
	if event.Reason != "" {
		payload["reason"] = event.Reason
	}
	if !event.OccurredAt.IsZero() {
		payload["occurred_at"] = event.OccurredAt.UTC().Format(time.RFC3339Nano)
	}

	return Envelope{
		ProtocolVersion: ProtocolVersion,
		ID:              generateID(),
		Type:            "event",
		Channel:         "task",
		Action:          "task.status.changed",
		Payload:         payload,
	}
}
