import { z } from "zod";
import { KeywordResearchService } from "@/server/features/keywords/services/KeywordResearchService";
import { mcpResponse } from "@/server/mcp/formatters";
import { buildProjectMeta } from "@/server/mcp/context";
import { optionalMetaOutputSchema } from "@/server/mcp/output-schemas";
import { withMcpProjectAuth } from "@/server/mcp/project-auth";
import {
  DEFAULT_LANGUAGE_CODE,
  DEFAULT_LOCATION_CODE,
  languageCodeSchema,
  locationCodeSchema,
  projectIdSchema,
} from "@/server/mcp/schemas";

const inputSchema = {
  projectId: projectIdSchema,
  keywords: z
    .array(z.string().min(1))
    .min(1)
    .max(100)
    .describe("Keywords to save (1-100)."),
  tags: z
    .array(z.string().min(1).max(64))
    .max(20)
    .optional()
    .describe(
      "Optional tags to attach to every saved keyword. Ask the user for explicit confirmation before using this, especially when saving many keywords or creating new tag names.",
    ),
  tagMode: z
    .enum(["append", "replace"])
    .optional()
    .describe(
      "How to apply tags. Defaults to append. Use replace to remove existing tags from these saved keywords before applying the provided tags.",
    ),
  locationCode: locationCodeSchema.optional(),
  languageCode: languageCodeSchema.optional(),
} as const;

type Args = z.infer<z.ZodObject<typeof inputSchema>>;

export const saveKeywordsTool = {
  name: "save_keywords",
  config: {
    title: "Save keywords",
    description:
      "Save keywords to a project's saved-keywords list. Uses no credits — does not call DataForSEO. Idempotent: re-saving an existing keyword is a no-op. If tags are provided, missing tags may be created. By default tags are appended; set tagMode=replace to remove existing tags from these saved keywords before applying the provided tags, which is useful for reorganizing keywords into page/topic clusters. Ask the user for confirmation before applying or replacing tags broadly.",
    inputSchema,
    outputSchema: {
      projectId: z.string(),
      savedCount: z.number(),
      keywords: z.array(z.string()),
      tags: z.array(z.string()),
      tagMode: z.enum(["append", "replace"]),
      locationCode: z.number(),
      languageCode: z.string(),
      ...optionalMetaOutputSchema,
    },
    annotations: {
      readOnlyHint: false,
      openWorldHint: false,
      destructiveHint: false,
    },
  },
  handler: withMcpProjectAuth(async (args: Args, context) => {
    if (args.tagMode === "replace" && (args.tags?.length ?? 0) === 0) {
      throw new Error("Replacement tags are required when tagMode is replace.");
    }

    const locationCode = args.locationCode ?? DEFAULT_LOCATION_CODE;
    const languageCode = args.languageCode ?? DEFAULT_LANGUAGE_CODE;

    await KeywordResearchService.saveKeywords({
      projectId: args.projectId,
      keywords: args.keywords,
      tags: args.tags,
      tagMode: args.tagMode ?? "append",
      locationCode,
      languageCode,
    });

    const tagText =
      args.tags && args.tags.length > 0
        ? ` with tag(s): ${args.tags.join(", ")}`
        : "";
    const modeText = args.tagMode === "replace" ? " Replaced tags." : "";

    return mcpResponse({
      text: `Saved ${args.keywords.length} keyword(s)${tagText} to project ${args.projectId}.${modeText}`,
      meta: buildProjectMeta(
        context,
        args.projectId,
        `/p/${args.projectId}/saved`,
      ),
      structuredContent: {
        projectId: args.projectId,
        savedCount: args.keywords.length,
        keywords: args.keywords,
        tags: args.tags ?? [],
        tagMode: args.tagMode ?? "append",
        locationCode,
        languageCode,
      },
    });
  }),
};
