package taskboard

import (
	"context"
	"fmt"
	"strings"
	"time"
)

// TaskChangeType is the transport-neutral event kind used by task callbacks.
type TaskChangeType string

const (
	TaskChangeCreated TaskChangeType = "created"
	TaskChangeUpdated TaskChangeType = "updated"
	TaskChangeDeleted TaskChangeType = "deleted"
)

// TaskChangeEvent is the stable callback payload that taskboard emits after a
// successful mutation. It is shaped so the same contract can back in-process
// realtime bridges today and out-of-process callbacks later.
type TaskChangeEvent struct {
	EventID    string
	EventType  TaskChangeType
	OccurredAt time.Time
	Context    ServiceContext
	ChannelID  string
	Tasks      []Task
	Task       Task
	TaskID     string
}

// TaskChangeSink receives task mutation callbacks behind a transport-neutral
// contract.
type TaskChangeSink interface {
	HandleTaskChange(ctx context.Context, event TaskChangeEvent)
}

func NewTaskCreatedEvent(requestContext ServiceContext, channelID string, tasks []Task) TaskChangeEvent {
	trimmedChannelID := strings.TrimSpace(channelID)
	copiedTasks := append([]Task(nil), tasks...)
	now := time.Now().UTC()
	return TaskChangeEvent{
		EventID:    newTaskChangeEventID(trimmedChannelID, now),
		EventType:  TaskChangeCreated,
		OccurredAt: now,
		Context:    requestContext,
		ChannelID:  trimmedChannelID,
		Tasks:      copiedTasks,
	}
}

func NewTaskUpdatedEvent(requestContext ServiceContext, task Task) TaskChangeEvent {
	now := time.Now().UTC()
	return TaskChangeEvent{
		EventID:    newTaskChangeEventID(task.ID, now),
		EventType:  TaskChangeUpdated,
		OccurredAt: now,
		Context:    requestContext,
		ChannelID:  strings.TrimSpace(task.ChannelID),
		Task:       task,
	}
}

func NewTaskDeletedEvent(requestContext ServiceContext, channelID string, taskID string) TaskChangeEvent {
	trimmedChannelID := strings.TrimSpace(channelID)
	trimmedTaskID := strings.TrimSpace(taskID)
	now := time.Now().UTC()
	return TaskChangeEvent{
		EventID:    newTaskChangeEventID(trimmedTaskID, now),
		EventType:  TaskChangeDeleted,
		OccurredAt: now,
		Context:    requestContext,
		ChannelID:  trimmedChannelID,
		TaskID:     trimmedTaskID,
	}
}

func newTaskChangeEventID(seed string, occurredAt time.Time) string {
	trimmedSeed := strings.TrimSpace(seed)
	if trimmedSeed == "" {
		trimmedSeed = "task"
	}
	return fmt.Sprintf("tce_%d_%s", occurredAt.UnixNano(), trimmedSeed)
}
