import { execFile } from "child_process";
import { promisify } from "util";
import { tool } from "@opencode-ai/plugin";

const execFileAsync = promisify(execFile);

// The endpoint behind @wix/mcp's SupportAndFeedback tool, which the local
// stdio @wix/mcp doesn't register. Relays to the #mcp-user-feedback Slack
// channel, attributed to the token's user.
const FEEDBACK_API_URL = "https://www.wixapis.com/mcp-serverless/v1/feedback";
const FEEDBACK_TIMEOUT_MS = 15_000;

const WIX_MCP_TOOLS = [
  "SearchWixSDKDocumentation",
  "ReadFullDocsArticle",
  "ReadFullDocsMethodSchema",
  "SearchWixAPISpec",
  "BrowseWixRESTDocsMenu",
  "CallWixSiteAPI",
  "ExecuteWixAPI",
];

// Lookbehind rather than \b so opencode's "wix-mcp_<tool>" form matches too.
const WIX_DOCS_CITATION_RE = new RegExp(
  `dev\\.wix\\.com|(?<![A-Za-z0-9])(?:${WIX_MCP_TOOLS.join("|")})\\b`,
);

const OUT_OF_SCOPE_RE = /\.md\b|\bskills?\b|@wix\/(?:patterns|design-system)\b/i;

export const MISSING_CITATION_REPLY =
  "Not sent: the report doesn't cite a dev.wix.com URL or the wix-mcp tool you called " +
  "(e.g. SearchWixSDKDocumentation, ReadFullDocsMethodSchema). Only wix-mcp and " +
  "dev.wix.com docs problems belong here — skill references, skill scripts, docs in " +
  "node_modules, and your own code are out of scope. If it is a wix-mcp problem, resend " +
  "with the citation; otherwise continue your task.";

export const OUT_OF_SCOPE_REPLY =
  "Not sent: the report mentions a skill, a .md reference, or @wix/patterns / " +
  "@wix/design-system docs — none of those are wix-mcp or dev.wix.com docs problems. If " +
  "part of it is a wix-mcp or dev.wix.com problem, resend only that part without " +
  "mentioning them; otherwise continue your task.";

async function getWixAccessToken(): Promise<string> {
  const { stdout } = await execFileAsync("wix", ["token", "--json"], {
    timeout: 30_000,
  });
  const { accessToken } = JSON.parse(stdout) as { accessToken?: string };
  if (!accessToken) {
    throw new Error("wix token returned empty accessToken");
  }
  return accessToken;
}

function buildProvenance(): string {
  const lines = [
    `Source: Codegen running on ${process.env.CODEGEN_ENVIRONMENT ?? "unknown environment"}`,
    process.env.CODEGEN_JOB_ID && `Codegen job id: ${process.env.CODEGEN_JOB_ID}`,
    process.env.CODEGEN_PROJECT_ID &&
      `Project id: ${process.env.CODEGEN_PROJECT_ID}`,
    process.env.CODEGEN_METASITE_ID &&
      `Meta site id: ${process.env.CODEGEN_METASITE_ID}`,
  ];
  return lines.filter(Boolean).join("\n");
}

export default tool({
  description:
    "Report a problem with the Wix docs (dev.wix.com, read through wix-mcp) or the wix-mcp " +
    "tools to the Wix MCP team: a search whose top results were off-target, a docs article " +
    "or example that is wrong or missing the fields you needed, a method schema that " +
    "doesn't match the installed SDK types, or a wix-mcp tool error. Include cases you " +
    "recovered from. Do NOT report skill references (SKILL.md, references/*.md), skill " +
    "scripts, package docs in node_modules, your own mistakes, or the user's request — " +
    "those aren't wix-mcp issues. Every report must cite the wix-mcp tool or dev.wix.com " +
    "URL involved. Call it at most ONCE per task, covering every friction point you've " +
    "hit so far.",
  args: {
    message: tool.schema
      .string()
      .min(1)
      .describe(
        "Plain-text report. For each friction point: the tool and exact input (search " +
          "term, dev.wix.com URL), what came back, what was wrong or missing, the workaround you " +
          "used, and what you expected. Then your best guess of where the fault lives " +
          "(search ranking / docs article or example / method schema / SDK typings / wix-mcp " +
          "tool) and whether you confirmed it. End with one line naming the most important " +
          "problem. No secrets or tokens.",
      ),
    requestId: tool.schema
      .string()
      .optional()
      .describe(
        "x-wix-request-id of a failed Wix API call this report relates to, if any.",
      ),
  },
  async execute(args) {
    if (!WIX_DOCS_CITATION_RE.test(args.message)) {
      return MISSING_CITATION_REPLY;
    }
    if (OUT_OF_SCOPE_RE.test(args.message)) {
      return OUT_OF_SCOPE_REPLY;
    }

    const message = [
      buildProvenance(),
      args.message,
      args.requestId && `request id: ${args.requestId}`,
    ]
      .filter(Boolean)
      .join("\n\n");

    try {
      const response = await fetch(FEEDBACK_API_URL, {
        method: "POST",
        headers: {
          Authorization: await getWixAccessToken(),
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ message }),
        signal: AbortSignal.timeout(FEEDBACK_TIMEOUT_MS),
      });
      if (!response.ok) {
        return `Failed to send the report (HTTP ${response.status}). Continue your task — do not retry.`;
      }
      return "Report sent to the Wix MCP team. Continue your task.";
    } catch (error) {
      const reason = error instanceof Error ? error.message : String(error);
      return `Failed to send the report (${reason}). Continue your task — do not retry.`;
    }
  },
});
