/* eslint-disable max-classes-per-file -- the AgentOS service and its tagged error form one adapter contract. */
import git from "@agentos-software/git";
import { agentOS as createAgentOsActor } from "@rivet-dev/agentos";
import type { AgentOSConfigInput } from "@rivet-dev/agentos";
import { Context, Effect, Layer, Schema } from "effect";

const withGitSoftware = (
  config: AgentOSConfigInput<undefined>
): AgentOSConfigInput<undefined> => ({
  ...config,
  software: [git, ...(config.software ?? [])],
});

export class AgentOsError extends Schema.TaggedErrorClass<AgentOsError>()(
  "AgentOsError",
  {
    cause: Schema.Defect(),
  }
) {}

export interface AgentOsOptions {
  readonly config?: AgentOSConfigInput<undefined>;
}

export class AgentOs extends Context.Service<
  AgentOs,
  {
    readonly createActor: (
      config?: AgentOSConfigInput<undefined>
    ) => Effect.Effect<
      ReturnType<typeof createAgentOsActor<undefined>>,
      AgentOsError
    >;
  }
>()("@code/primitives/agent-os/AgentOs") {
  static readonly layer = Layer.succeed(
    AgentOs,
    AgentOs.of({
      createActor: Effect.fn("AgentOs.createActor")(function* createActor(
        config: AgentOSConfigInput<undefined> = {}
      ) {
        return yield* Effect.try({
          catch: (cause) => new AgentOsError({ cause }),
          try: () => createAgentOsActor<undefined>(withGitSoftware(config)),
        });
      }),
    })
  );
}

export const makeAgentOsLayer = (options: AgentOsOptions = {}) =>
  Layer.succeed(
    AgentOs,
    AgentOs.of({
      createActor: Effect.fn("AgentOs.createActor")(function* createActor(
        config: AgentOSConfigInput<undefined> = options.config ?? {}
      ) {
        return yield* Effect.try({
          catch: (cause) => new AgentOsError({ cause }),
          try: () => createAgentOsActor<undefined>(withGitSoftware(config)),
        });
      }),
    })
  );

export const createAgentOsActorEffect = Effect.fn("createAgentOsActorEffect")(
  function* createAgentOsActorEffect(config?: AgentOSConfigInput<undefined>) {
    const agentOs = yield* AgentOs;
    return yield* agentOs.createActor(config);
  }
);
