import { parseAgentEnv } from "@code/env/agent";
import { defineTool } from "@flue/runtime";
import { ConvexHttpClient } from "convex/browser";
import { makeFunctionReference } from "convex/server";
import * as v from "valibot";

const listProjectsRef = makeFunctionReference<
  "query",
  { organizationId: string; token: string },
  { _id: string; name: string; description: string | null }[]
>("signalRouting:listProjects");

const listEvidenceRef = makeFunctionReference<
  "query",
  { organizationId: string; token: string },
  { messageId: string; rawText: string; createdAt: number }[]
>("signalRouting:listEvidence");

const createSignalRef = makeFunctionReference<
  "mutation",
  {
    organizationId: string;
    projectId: string;
    messageIds: string[];
    problemStatement: {
      title: string;
      summary: string;
      desiredOutcome: string;
      constraints: string[];
    };
    processedByAgentInstanceId: string;
    token: string;
  },
  { signalId: string }
>("signalRouting:createSignal");

const listWorksRef = makeFunctionReference<
  "query",
  { organizationId: string; projectId: string; token: string },
  { _id: string; title: string; objective: string; status: "proposed" }[]
>("works:listProposedForAgent");

const createWorkRef = makeFunctionReference<
  "mutation",
  { organizationId: string; signalId: string; token: string },
  { created: boolean; workId: string }
>("works:createFromSignal");

const attachSignalRef = makeFunctionReference<
  "mutation",
  { organizationId: string; signalId: string; workId: string; token: string },
  { attached: boolean; workId: string }
>("works:attachSignalToWork");

export const createSliceOneTools = (
  organizationId: string,
  runtimeEnv: Record<string, string | undefined>
) => {
  const env = parseAgentEnv(runtimeEnv);
  const client = new ConvexHttpClient(env.CONVEX_URL);
  const token = env.FLUE_DB_TOKEN;

  return [
    defineTool({
      description: "List the projects available in this organization.",
      name: "list_projects",
      async run() {
        return await client.query(listProjectsRef, { organizationId, token });
      },
    }),
    defineTool({
      description:
        "List exact admitted user messages that have not yet been used as Signal evidence.",
      name: "list_signal_evidence",
      async run() {
        return await client.query(listEvidenceRef, { organizationId, token });
      },
    }),
    defineTool({
      description:
        "Create one structured Signal from exact message IDs. Use only for actionable intent.",
      input: v.object({
        messageIds: v.array(v.string()),
        problemStatement: v.object({
          constraints: v.array(v.string()),
          desiredOutcome: v.string(),
          summary: v.string(),
          title: v.string(),
        }),
        projectId: v.string(),
      }),
      name: "create_signal",
      async run({ input }) {
        return await client.mutation(createSignalRef, {
          messageIds: input.messageIds,
          organizationId,
          problemStatement: input.problemStatement,
          processedByAgentInstanceId: organizationId,
          projectId: input.projectId,
          token,
        });
      },
    }),
    defineTool({
      description:
        "List proposed Work for a project before deciding whether a new Signal belongs to existing Work.",
      input: v.object({ projectId: v.string() }),
      name: "list_proposed_work",
      async run({ input }) {
        return await client.query(listWorksRef, {
          organizationId,
          projectId: input.projectId,
          token,
        });
      },
    }),
    defineTool({
      description:
        "Create one proposed Work from a Signal. This is idempotent for the same Signal.",
      input: v.object({ signalId: v.string() }),
      name: "create_work_from_signal",
      async run({ input }) {
        return await client.mutation(createWorkRef, {
          organizationId,
          signalId: input.signalId,
          token,
        });
      },
    }),
    defineTool({
      description:
        "Attach a Signal to existing proposed Work when it describes the same desired outcome.",
      input: v.object({ signalId: v.string(), workId: v.string() }),
      name: "attach_signal_to_work",
      async run({ input }) {
        return await client.mutation(attachSignalRef, {
          organizationId,
          signalId: input.signalId,
          token,
          workId: input.workId,
        });
      },
    }),
  ];
};
