// Package manual implements the "manual" trigger: any ManualEvent fires a
// deploy. No per-workload config — the trigger always matches its kind.
package manual

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/alexei/tinyforge/internal/workload/plugin"
)

type trigger struct{}

func init() { plugin.RegisterTrigger(&trigger{}) }

func (*trigger) Kind() string { return "manual" }

func (*trigger) SchemaSample() any { return struct{}{} }

func (*trigger) Validate(cfg json.RawMessage) error {
	// Manual triggers have no config; accept empty or a small valid JSON
	// blob. The cap prevents an admin from pinning a 1 MiB blob to a
	// trigger row that gets serialized on every read.
	if len(cfg) == 0 {
		return nil
	}
	if len(cfg) > 1024 {
		return fmt.Errorf("manual trigger: config must be empty or a small JSON value (got %d bytes)", len(cfg))
	}
	if !json.Valid(cfg) {
		return fmt.Errorf("manual trigger: invalid json")
	}
	return nil
}

func (*trigger) Match(ctx context.Context, deps plugin.Deps, w plugin.Workload, evt plugin.InboundEvent) (*plugin.DeploymentIntent, error) {
	if evt.Kind != "manual" || evt.Manual == nil {
		return nil, nil
	}
	actor := evt.Manual.Actor
	if actor == "" {
		actor = "manual"
	}
	meta := map[string]string{}
	if evt.Manual.Note != "" {
		meta["note"] = evt.Manual.Note
	}
	return &plugin.DeploymentIntent{
		Reason:      "manual",
		Reference:   evt.Manual.Reference,
		Metadata:    meta,
		TriggeredAt: time.Now().UTC(),
		TriggeredBy: actor,
	}, nil
}
