import { CloseBotClient, ok, err } from "../client.js";
import type { ToolDefinition, ToolResult, BotDto, CreateBotInput, AiCreateBotInput, UpdateBotInput, ExportBotResponse, SaveBotInput, SaveBotResponse, PublishBotResponse, ToolInputDto, BotToolDto, BotTemplateDto, UpdateVersionInput } from "../types.js";

export const tools: ToolDefinition[] = [
  {
    name: "list_bots",
    description: "List all bots in the agency",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "get_bot",
    description: "Get a specific bot by ID",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
      },
      required: ["id"],
    },
  },
  {
    name: "create_bot",
    description: "Create a new bot. Can use a template ID or import KDL.",
    inputSchema: {
      type: "object",
      properties: {
        name: { type: "string", description: "The name of the new bot" },
        templateId: { type: "string", description: "Template ID to create from" },
        importKdl: { type: "string", description: "KDL template to import" },
        folderId: { type: "string", description: "Folder ID to place the bot in" },
        category: { type: "string", description: "Bot category (GHL, WebHook, etc.)" },
      },
      required: ["name"],
    },
  },
  {
    name: "create_bot_with_ai",
    description: "Create a new bot using AI-generated steps from a text description",
    inputSchema: {
      type: "object",
      properties: {
        name: { type: "string", description: "The name of the new bot" },
        description: { type: "string", description: "Prompt describing what the bot should do" },
        category: { type: "string", description: "Source category (GHL, WebHook, etc.)" },
        folderId: { type: "string", description: "Folder ID to place the bot in" },
      },
      required: ["name", "description"],
    },
  },
  {
    name: "update_bot",
    description: "Update bot fields. Only non-null fields are updated.",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        name: { type: "string", description: "New name" },
        favorite: { type: "boolean", description: "Whether the bot is favorited" },
        trash: { type: "boolean", description: "Whether the bot is trashed" },
        locked: { type: "boolean", description: "Whether the bot is locked" },
        rescheduling: { type: "boolean", description: "Enable conversation rescheduling" },
        folderId: { type: "string", description: "Folder ID" },
        category: { type: "string", description: "Category" },
        followUpActive: { type: "boolean", description: "Enable follow-ups" },
        smartFollowUp: { type: "boolean", description: "Enable smart follow-ups" },
        followUpRepeat: { type: "boolean", description: "Repeat last follow-up sequence" },
        followUpVarianceMinutes: { type: "number", description: "Variance minutes for follow-ups" },
        followUpExtraPrompt: { type: "string", description: "Extra prompt for follow-ups" },
      },
      required: ["id"],
    },
  },
  {
    name: "delete_bot",
    description: "Delete a bot by ID",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
      },
      required: ["id"],
    },
  },
  {
    name: "duplicate_bot",
    description: "Duplicate an existing bot",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID to duplicate" },
      },
      required: ["id"],
    },
  },
  {
    name: "export_bot",
    description: "Export a bot as KDL. Optionally specify a version.",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        botVersion: { type: "string", description: "Version (x.y.z). Defaults to latest." },
      },
      required: ["id"],
    },
  },
  {
    name: "publish_bot",
    description: "Publish a bot to make it live",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
      },
      required: ["id"],
    },
  },
  {
    name: "save_bot",
    description: "Save bot steps (the bot flow definition)",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        botSteps: { type: "object", description: "The bot steps/flow data" },
      },
      required: ["id", "botSteps"],
    },
  },
  {
    name: "save_bot_tools",
    description: "Save the tools configuration for a bot",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        tools: {
          type: "array",
          description: "Array of tool configurations",
          items: {
            type: "object",
            properties: {
              type: { type: "string", description: "Tool type" },
              enabled: { type: "boolean", description: "Whether enabled" },
              options: { type: "object", description: "Tool options" },
            },
          },
        },
      },
      required: ["id", "tools"],
    },
  },
  {
    name: "get_bot_steps",
    description: "Get the steps/flow for a specific bot version",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        botVersion: { type: "string", description: "Version (x.y.z)" },
      },
      required: ["id"],
    },
  },
  {
    name: "get_node_descriptors",
    description: "Get all available node descriptors for the bot builder",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "update_bot_version",
    description: "Update a specific bot version (rename or import KDL)",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        version: { type: "string", description: "The version ID" },
        name: { type: "string", description: "New version name" },
        importKdl: { type: "string", description: "KDL to import into this version" },
      },
      required: ["id", "version"],
    },
  },
  {
    name: "get_bot_templates",
    description: "List all available bot templates",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "attach_source_to_bot",
    description: "Attach a source to a bot with optional tag/channel config",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        sourceId: { type: "string", description: "The source ID" },
        enabled: { type: "boolean", description: "Whether the attachment is enabled" },
        channels: { type: "array", items: { type: "string" }, description: "Channel list" },
        personaNameOverride: { type: "string", description: "Persona name override" },
      },
      required: ["id", "sourceId"],
    },
  },
  {
    name: "detach_source_from_bot",
    description: "Detach a source from a bot",
    inputSchema: {
      type: "object",
      properties: {
        id: { type: "string", description: "The bot ID" },
        sourceId: { type: "string", description: "The source ID" },
      },
      required: ["id", "sourceId"],
    },
  },
  {
    name: "get_bbb_templates",
    description: "Get bot builder builder template names",
    inputSchema: { type: "object", properties: {} },
  },
];

export async function handler(
  client: CloseBotClient,
  name: string,
  args: Record<string, unknown>
): Promise<ToolResult> {
  try {
    switch (name) {
      case "list_bots":
        return ok(await client.get<BotDto[]>("/bot"));

      case "get_bot":
        return ok(await client.get<BotDto>(`/bot/${args.id}`));

      case "create_bot": {
        const body: CreateBotInput = {
          name: args.name as string,
          templateId: args.templateId as string | undefined,
          importKdl: args.importKdl as string | undefined,
          folderId: args.folderId as string | undefined,
          category: args.category as string | undefined,
        };
        return ok(await client.post<BotDto>("/bot", body));
      }

      case "create_bot_with_ai": {
        const body: AiCreateBotInput = {
          name: args.name as string,
          description: args.description as string,
          category: args.category as string | undefined,
          folderId: args.folderId as string | undefined,
        };
        return ok(await client.post<BotDto>("/bot/ai", body));
      }

      case "update_bot": {
        const { id, ...rest } = args;
        const body: UpdateBotInput = {};
        if (rest.name !== undefined) body.name = rest.name as string;
        if (rest.favorite !== undefined) body.favorite = rest.favorite as boolean;
        if (rest.trash !== undefined) body.trash = rest.trash as boolean;
        if (rest.locked !== undefined) body.locked = rest.locked as boolean;
        if (rest.rescheduling !== undefined) body.rescheduling = rest.rescheduling as boolean;
        if (rest.folderId !== undefined) body.folderId = rest.folderId as string;
        if (rest.category !== undefined) body.category = rest.category as string;
        if (rest.followUpActive !== undefined) body.followUpActive = rest.followUpActive as boolean;
        if (rest.smartFollowUp !== undefined) body.smartFollowUp = rest.smartFollowUp as boolean;
        if (rest.followUpRepeat !== undefined) body.followUpRepeat = rest.followUpRepeat as boolean;
        if (rest.followUpVarianceMinutes !== undefined)
          body.followUpVarianceMinutes = rest.followUpVarianceMinutes as number;
        if (rest.followUpExtraPrompt !== undefined)
          body.followUpExtraPrompt = rest.followUpExtraPrompt as string;
        return ok(await client.put<BotDto>(`/bot/${id}`, body));
      }

      case "delete_bot":
        return ok(await client.delete(`/bot/${args.id}`));

      case "duplicate_bot":
        return ok(await client.post<BotDto>(`/bot/${args.id}/duplicate`));

      case "export_bot":
        return ok(
          await client.get<ExportBotResponse>(`/bot/${args.id}/export`, {
            botVersion: args.botVersion,
          })
        );

      case "publish_bot":
        return ok(await client.post<PublishBotResponse>(`/bot/${args.id}/publish`));

      case "save_bot": {
        const body: SaveBotInput = { botSteps: args.botSteps };
        return ok(await client.post<SaveBotResponse>(`/bot/${args.id}/save`, body));
      }

      case "save_bot_tools":
        return ok(
          await client.post<BotToolDto[]>(
            `/bot/${args.id}/saveTools`,
            args.tools as ToolInputDto[]
          )
        );

      case "get_bot_steps":
        return ok(
          await client.get(`/bot/${args.id}/steps`, {
            botVersion: args.botVersion,
          })
        );

      case "get_node_descriptors":
        return ok(await client.get("/bot/nodeDescriptors"));

      case "update_bot_version": {
        const body: UpdateVersionInput = {};
        if (args.name !== undefined) body.name = args.name as string;
        if (args.importKdl !== undefined) body.importKdl = args.importKdl as string;
        return ok(
          await client.put(`/bot/${args.id}/version/${args.version}`, body)
        );
      }

      case "get_bot_templates":
        return ok(await client.get<BotTemplateDto[]>("/botTemplates"));

      case "attach_source_to_bot": {
        const body: Record<string, unknown> = {};
        if (args.enabled !== undefined) body.enabled = args.enabled;
        if (args.channels !== undefined) body.channels = args.channels;
        if (args.personaNameOverride !== undefined)
          body.personaNameOverride = args.personaNameOverride;
        return ok(
          await client.post(`/bot/${args.id}/source/${args.sourceId}`, body)
        );
      }

      case "detach_source_from_bot":
        return ok(
          await client.delete(`/bot/${args.id}/source/${args.sourceId}`)
        );

      case "get_bbb_templates":
        return ok(await client.get<string[]>("/bot/bbb/templates"));

      default:
        return err(`Unknown tool: ${name}`);
    }
  } catch (error) {
    return err(error);
  }
}
