// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package event

import (
	"time"

	"git.secluded.site/np/internal/goal"
	"git.secluded.site/np/internal/task"
	"git.secluded.site/np/internal/timeutil"
)

// GoalSnapshot captures relevant goal fields for event payloads.
type GoalSnapshot struct {
	Title       string    `json:"title"`
	Description string    `json:"description"`
	UpdatedAt   time.Time `json:"updated_at"`
}

// GoalSetPayload records a goal being established.
type GoalSetPayload struct {
	Goal GoalSnapshot `json:"goal"`
}

// GoalUpdatedPayload records a goal changing.
type GoalUpdatedPayload struct {
	Before GoalSnapshot `json:"goal_before"`
	After  GoalSnapshot `json:"goal_after"`
}

// TaskAddedPayload records a newly added task.
type TaskAddedPayload struct {
	Task task.Task `json:"task"`
}

// TaskStateSnapshot captures mutable task fields for updates.
type TaskStateSnapshot struct {
	Title       string    `json:"title"`
	Description string    `json:"description"`
	UpdatedAt   time.Time `json:"updated_at"`
}

// TaskUpdatedPayload captures title/description edits.
type TaskUpdatedPayload struct {
	TaskID string            `json:"task_id"`
	Before TaskStateSnapshot `json:"before"`
	After  TaskStateSnapshot `json:"after"`
}

// TaskStatusChangedPayload captures status transitions.
type TaskStatusChangedPayload struct {
	TaskID       string      `json:"task_id"`
	Title        string      `json:"title"`
	StatusBefore task.Status `json:"status_before"`
	StatusAfter  task.Status `json:"status_after"`
	UpdatedAt    time.Time   `json:"updated_at"`
}

// GoalSnapshotFrom converts a goal document into an event snapshot.
func GoalSnapshotFrom(doc goal.Document) GoalSnapshot {
	return GoalSnapshot{
		Title:       doc.Title,
		Description: doc.Description,
		UpdatedAt:   timeutil.EnsureUTC(doc.UpdatedAt),
	}
}

// TaskStateSnapshotFrom converts a task into a mutable-field snapshot.
func TaskStateSnapshotFrom(t task.Task) TaskStateSnapshot {
	return TaskStateSnapshot{
		Title:       t.Title,
		Description: t.Description,
		UpdatedAt:   timeutil.EnsureUTC(t.UpdatedAt),
	}
}

// BuildGoalSet constructs AppendInput for goal_set events.
func BuildGoalSet(command, reason string, doc goal.Document) AppendInput {
	return AppendInput{
		Type:    TypeGoalSet,
		Command: command,
		Reason:  reason,
		Payload: GoalSetPayload{
			Goal: GoalSnapshotFrom(doc),
		},
	}
}

// BuildGoalUpdated constructs AppendInput for goal_updated events.
func BuildGoalUpdated(command, reason string, before, after goal.Document) AppendInput {
	return AppendInput{
		Type:    TypeGoalUpdated,
		Command: command,
		Reason:  reason,
		Payload: GoalUpdatedPayload{
			Before: GoalSnapshotFrom(before),
			After:  GoalSnapshotFrom(after),
		},
	}
}

// BuildTaskAdded constructs AppendInput for task_added events.
func BuildTaskAdded(command, reason string, t task.Task) AppendInput {
	return AppendInput{
		Type:    TypeTaskAdded,
		Command: command,
		Reason:  reason,
		Payload: TaskAddedPayload{
			Task: t,
		},
	}
}

// BuildTaskUpdated constructs AppendInput for task_updated events.
func BuildTaskUpdated(command, reason, taskID string, before, after task.Task) AppendInput {
	return AppendInput{
		Type:    TypeTaskUpdated,
		Command: command,
		Reason:  reason,
		Payload: TaskUpdatedPayload{
			TaskID: taskID,
			Before: TaskStateSnapshotFrom(before),
			After:  TaskStateSnapshotFrom(after),
		},
	}
}

// BuildTaskStatusChanged constructs AppendInput for task_status_changed events.
func BuildTaskStatusChanged(command, reason string, before task.Task, after task.Task) AppendInput {
	return AppendInput{
		Type:    TypeTaskStatusChange,
		Command: command,
		Reason:  reason,
		Payload: TaskStatusChangedPayload{
			TaskID:       after.ID,
			Title:        after.Title,
			StatusBefore: before.Status,
			StatusAfter:  after.Status,
			UpdatedAt:    timeutil.EnsureUTC(after.UpdatedAt),
		},
	}
}
