src/automata@event@builtin@body.erl

-module(automata@event@builtin@body).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/event/builtin/body.gleam").
-export([scheduled/3, file_system/1, manual/2, custom/2, derived_source_kind/1, derived_source/2, new/4, scheduled_event/4, kind/1]).
-export_type([event_body/0, schedule_kind/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

-type event_body() :: {scheduled,
        binary(),
        automata@schedule@ast:valid_date_time(),
        schedule_kind()} |
    {file_system, automata@fsevent@event:watch_event()} |
    {manual, gleam@option:option(binary()), gleam@option:option(binary())} |
    {custom, binary(), gleam@dict:dict(binary(), binary())}.

-type schedule_kind() :: cron_schedule | r_rule_schedule.

-file("src/automata/event/builtin/body.gleam", 57).
-spec scheduled(
    binary(),
    automata@schedule@ast:valid_date_time(),
    schedule_kind()
) -> event_body().
scheduled(Plan_id, Fired_at, Schedule_kind) ->
    {scheduled, Plan_id, Fired_at, Schedule_kind}.

-file("src/automata/event/builtin/body.gleam", 66).
?DOC(" Wrap an `automata/fsevent` `WatchEvent` in the canonical body.\n").
-spec file_system(automata@fsevent@event:watch_event()) -> event_body().
file_system(Event) ->
    {file_system, Event}.

-file("src/automata/event/builtin/body.gleam", 70).
-spec manual(gleam@option:option(binary()), gleam@option:option(binary())) -> event_body().
manual(Reason, Actor) ->
    {manual, Reason, Actor}.

-file("src/automata/event/builtin/body.gleam", 77).
-spec custom(binary(), gleam@dict:dict(binary(), binary())) -> event_body().
custom(Kind, Attributes) ->
    {custom, Kind, Attributes}.

-file("src/automata/event/builtin/body.gleam", 152).
?DOC(" Map an `EventBody` to its canonical `SourceKind`.\n").
-spec derived_source_kind(event_body()) -> automata@event@source:source_kind().
derived_source_kind(Body) ->
    case Body of
        {scheduled, _, _, _} ->
            schedule_source;

        {file_system, _} ->
            file_system_source;

        {manual, _, _} ->
            manual_source;

        {custom, Name, _} ->
            {custom_source, Name}
    end.

-file("src/automata/event/builtin/body.gleam", 147).
?DOC(
    " Derive the canonical `Source` for an `EventBody`. Exposed so that\n"
    " callers building events via `event.new` (for advanced cases like\n"
    " attaching a source name) can stay consistent with `body.new`.\n"
).
-spec derived_source(event_body(), binary()) -> automata@event@source:source().
derived_source(Body, Source_id) ->
    automata@event@source:new(derived_source_kind(Body), Source_id).

-file("src/automata/event/builtin/body.gleam", 90).
?DOC(
    " Construct a `BuiltinEvent` whose `source.kind` is derived from\n"
    " `body`. This is the only sanctioned constructor for `BuiltinEvent`\n"
    " because it makes source/body misclassification unrepresentable —\n"
    " `Scheduled` always pairs with `ScheduleSource`, `FileSystem(_)` with\n"
    " `FileSystemSource`, `Custom(\"vendor.kind\", _)` with\n"
    " `CustomSource(\"vendor.kind\")`, etc.\n"
).
-spec new(
    binary(),
    automata@schedule@ast:valid_date_time(),
    binary(),
    event_body()
) -> automata@event:event(event_body()).
new(Id, Occurred_at, Source_id, Body) ->
    {event,
        Id,
        Occurred_at,
        derived_source(Body, Source_id),
        Body,
        automata@event@metadata:empty()}.

-file("src/automata/event/builtin/body.gleam", 126).
?DOC(
    " Build a `Scheduled` `BuiltinEvent` from a single `(id, plan_id, at,\n"
    " schedule_kind)` tuple.\n"
    "\n"
    " Equivalent to:\n"
    "\n"
    " ```gleam\n"
    " new(\n"
    "   id: id,\n"
    "   occurred_at: at,\n"
    "   source_id: plan_id,\n"
    "   body: scheduled(plan_id: plan_id, fired_at: at, schedule_kind: kind),\n"
    " )\n"
    " ```\n"
    "\n"
    " In the common case `source_id` equals `plan_id` and `occurred_at`\n"
    " equals `fired_at`, so the verbose form forces the caller to type the\n"
    " same value twice. This smart constructor halves the surface and\n"
    " removes the \"are these intentionally different?\" cognitive load.\n"
    " Reach for `new/4` only when the two values genuinely differ\n"
    " (delayed dispatch recorded after the fact, fan-out under a\n"
    " different `source_id`, etc.).\n"
).
-spec scheduled_event(
    binary(),
    binary(),
    automata@schedule@ast:valid_date_time(),
    schedule_kind()
) -> automata@event:event(event_body()).
scheduled_event(Id, Plan_id, At, Schedule_kind) ->
    new(Id, At, Plan_id, scheduled(Plan_id, At, Schedule_kind)).

-file("src/automata/event/builtin/body.gleam", 169).
-spec op_label(automata@fsevent@ast:op()) -> binary().
op_label(Op) ->
    _pipe = automata@fsevent@op:op_to_string(Op),
    string:lowercase(_pipe).

-file("src/automata/event/builtin/body.gleam", 161).
-spec file_system_op_label(automata@fsevent@event:watch_event()) -> binary().
file_system_op_label(Event) ->
    _pipe = Event,
    _pipe@1 = automata@fsevent@event:event_ops(_pipe),
    _pipe@2 = automata@fsevent@op:to_list(_pipe@1),
    _pipe@3 = gleam@list:map(_pipe@2, fun op_label/1),
    gleam@string:join(_pipe@3, <<"+"/utf8>>).

-file("src/automata/event/builtin/body.gleam", 48).
?DOC(
    " Stable string label for routing tables, metrics, and structured logs.\n"
    "\n"
    " `FileSystem(_)` becomes `\"file_system:create\"` for a single-op\n"
    " event, `\"file_system:create+write\"` when several ops are present\n"
    " (lowercase ops joined by `+` in canonical order). `Custom(\"kind\", _)`\n"
    " becomes `\"custom:kind\"`.\n"
).
-spec kind(event_body()) -> binary().
kind(Body) ->
    case Body of
        {scheduled, _, _, _} ->
            <<"scheduled"/utf8>>;

        {file_system, Event} ->
            <<"file_system:"/utf8, (file_system_op_label(Event))/binary>>;

        {manual, _, _} ->
            <<"manual"/utf8>>;

        {custom, Name, _} ->
            <<"custom:"/utf8, Name/binary>>
    end.