import { HttpApiBuilder } from "effect/unstable/httpapi";
import { Context, Effect } from "effect";

import { addGroup, capture } from "@executor-js/api";
import type { GraphqlPluginExtension } from "../sdk/plugin";
import { GraphqlGroup } from "./group";

// ---------------------------------------------------------------------------
// Service tag
//
// Holds the plugin's extension. The host app provides an already-wrapped
// extension via `Layer.succeed(GraphqlExtensionService, executor.graphql)`.
// Handlers see plugin SDK errors in the typed channel (matched by
// `.addError(...)` on the group) and `InternalError` for `StorageError`
// translated by `capture` at the HTTP edge.
// ---------------------------------------------------------------------------

export class GraphqlExtensionService extends Context.Service<
  GraphqlExtensionService,
  GraphqlPluginExtension
>()("GraphqlExtensionService") {}

// ---------------------------------------------------------------------------
// Composed API — core + graphql group
// ---------------------------------------------------------------------------

const ExecutorApiWithGraphql = addGroup(GraphqlGroup);

// ---------------------------------------------------------------------------
// Handlers
// ---------------------------------------------------------------------------

export const GraphqlHandlers = HttpApiBuilder.group(ExecutorApiWithGraphql, "graphql", (handlers) =>
  handlers
    .handle("addIntegration", ({ payload }) =>
      capture(
        Effect.gen(function* () {
          const ext = yield* GraphqlExtensionService;
          const result = yield* ext.addIntegration({
            endpoint: payload.endpoint,
            slug: payload.slug,
            name: payload.name,
            description: payload.description,
            introspectionJson: payload.introspectionJson,
            headers: payload.headers,
            queryParams: payload.queryParams,
            authenticationTemplate: payload.authenticationTemplate,
          });
          return { slug: result.slug, name: result.name };
        }),
      ),
    )
    .handle("getIntegration", ({ params: path }) =>
      capture(
        Effect.gen(function* () {
          const ext = yield* GraphqlExtensionService;
          return yield* ext.getIntegration(path.slug);
        }),
      ),
    )
    .handle("getConfig", ({ params: path }) =>
      capture(
        Effect.gen(function* () {
          const ext = yield* GraphqlExtensionService;
          const config = yield* ext.getConfig(path.slug);
          return config
            ? {
                endpoint: config.endpoint,
                name: config.name,
                headers: config.headers ? { ...config.headers } : undefined,
                queryParams: config.queryParams ? { ...config.queryParams } : undefined,
                authenticationTemplate: [...config.authenticationTemplate],
              }
            : null;
        }),
      ),
    )
    .handle("configure", ({ params: path, payload }) =>
      capture(
        Effect.gen(function* () {
          const ext = yield* GraphqlExtensionService;
          const authenticationTemplate = yield* ext.configureAuth(path.slug, {
            authenticationTemplate: payload.authenticationTemplate,
            mode: payload.mode ?? "merge",
          });
          return { authenticationTemplate: [...authenticationTemplate] };
        }),
      ),
    ),
);
