export const DOCYRUS_WEB_BROWSER_EXTENSION_NAME = "docyrus-web-browser";
export const DOCYRUS_WEB_BROWSER_TAG = "docyrus_web_browser";
export const DOCYRUS_WEB_BROWSER_OPEN = `<${DOCYRUS_WEB_BROWSER_TAG}>`;
export const DOCYRUS_WEB_BROWSER_CLOSE = `</${DOCYRUS_WEB_BROWSER_TAG}>`;
export const DOCYRUS_WEB_BROWSER_RESULT_TAG = "docyrus_web_browser_result";
export const DOCYRUS_WEB_BROWSER_RESULT_OPEN = `<${DOCYRUS_WEB_BROWSER_RESULT_TAG}>`;
export const DOCYRUS_WEB_BROWSER_RESULT_CLOSE = `</${DOCYRUS_WEB_BROWSER_RESULT_TAG}>`;
export const WEB_PREVIEW_CONTEXT_TOOL = "web_preview_context";
export const WEB_PREVIEW_PLAYWRIGHT_TOOL = "web_preview_playwright";

export const DOCYRUS_WEB_BROWSER_TOOL_NAMES = [
  WEB_PREVIEW_CONTEXT_TOOL,
  WEB_PREVIEW_PLAYWRIGHT_TOOL,
] as const;

export type IDocyrusWebBrowserToolName = typeof DOCYRUS_WEB_BROWSER_TOOL_NAMES[number];

export interface IDocyrusWebBrowserToolRequest {
  tool: IDocyrusWebBrowserToolName;
  input?: Record<string, unknown>;
}

export interface IDocyrusWebBrowserToolResponsePrompt {
  tool: IDocyrusWebBrowserToolName;
  request?: Record<string, unknown>;
  status: "success" | "error";
  output?: unknown;
  errorText?: string;
}

export interface IDocyrusWebBrowserClientToolInfo {
  name: IDocyrusWebBrowserToolName;
  description: string;
  inputSchema?: Record<string, unknown>;
}

export const DOCYRUS_WEB_BROWSER_CLIENT_TOOLS: IDocyrusWebBrowserClientToolInfo[] = [
  {
    name: WEB_PREVIEW_CONTEXT_TOOL,
    description:
      "Inspect the current Docyrus web preview state before automation. Prefer this first when preview availability or bridge state is unknown.",
    inputSchema: {
      type: "object",
      properties: {
        includeSnapshot: { type: "boolean" },
      },
      additionalProperties: false,
    },
  },
  {
    name: WEB_PREVIEW_PLAYWRIGHT_TOOL,
    description:
      "Run Playwright-style actions against the Docyrus web preview. Prefer structured steps over raw scripts.",
    inputSchema: {
      type: "object",
      properties: {
        script: { type: "string" },
        steps: {
          type: "array",
          items: {
            type: "object",
            properties: {
              action: { type: "string" },
              selector: { type: "string" },
              url: { type: "string" },
              value: { type: "string" },
              values: {
                type: "array",
                items: { type: "string" },
              },
              key: { type: "string" },
              attribute: { type: "string" },
              timeoutMs: { type: "number" },
              state: { type: "string" },
            },
            additionalProperties: true,
          },
        },
        timeoutMs: { type: "number" },
        stopOnError: { type: "boolean" },
      },
      additionalProperties: true,
    },
  },
];

function hashString(value: string): string {
  let hash = 0;
  for (let index = 0; index < value.length; index += 1) {
    hash = ((hash << 5) - hash) + value.charCodeAt(index);
    hash |= 0;
  }
  return Math.abs(hash).toString(36);
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

export function isDocyrusWebBrowserToolName(value: unknown): value is IDocyrusWebBrowserToolName {
  return DOCYRUS_WEB_BROWSER_TOOL_NAMES.some((toolName) => toolName === value);
}

export function normalizeDocyrusWebBrowserToolRequest(value: unknown): IDocyrusWebBrowserToolRequest | undefined {
  if (!isRecord(value) || !isDocyrusWebBrowserToolName(value.tool)) {
    return undefined;
  }

  return {
    tool: value.tool,
    input: isRecord(value.input) ? value.input : undefined,
  };
}

export function serializeDocyrusWebBrowserToolRequest(request: IDocyrusWebBrowserToolRequest): string {
  return `${DOCYRUS_WEB_BROWSER_OPEN}\n${JSON.stringify(request, null, 2)}\n${DOCYRUS_WEB_BROWSER_CLOSE}`;
}

export function createDocyrusWebBrowserToolCallId(request: IDocyrusWebBrowserToolRequest): string {
  return `docyrus_web_browser_${hashString(JSON.stringify(request))}`;
}

export function parseDocyrusWebBrowserRequestFromText(text: string): IDocyrusWebBrowserToolRequest | undefined {
  const trimmed = text.trim();
  if (!trimmed.startsWith(DOCYRUS_WEB_BROWSER_OPEN) || !trimmed.endsWith(DOCYRUS_WEB_BROWSER_CLOSE)) {
    return undefined;
  }

  const body = trimmed.slice(DOCYRUS_WEB_BROWSER_OPEN.length, trimmed.length - DOCYRUS_WEB_BROWSER_CLOSE.length).trim();
  if (!body) {
    return undefined;
  }

  try {
    return normalizeDocyrusWebBrowserToolRequest(JSON.parse(body));
  } catch {
    return undefined;
  }
}

export function buildDocyrusWebBrowserProtocolInstructions(): string {
  return [
    "When you need to inspect or automate the Docyrus web preview in server-backed sessions, use the docyrus-web-browser client tools.",
    "Do not use `docyrus chrome` or any visible Chrome DevTools workflow in this environment.",
    `Instead, output only a single ${DOCYRUS_WEB_BROWSER_OPEN}...${DOCYRUS_WEB_BROWSER_CLOSE} block and nothing else in the assistant message.`,
    "Inside that block, emit strict JSON with this shape:",
    "{\"tool\":\"web_preview_context\",\"input\":{\"includeSnapshot\":true}}",
    "or",
    "{\"tool\":\"web_preview_playwright\",\"input\":{\"steps\":[{\"action\":\"goto\",\"url\":\"/login\"},{\"action\":\"fill\",\"selector\":\"input[name='email']\",\"value\":\"demo@example.com\"}],\"timeoutMs\":10000,\"stopOnError\":true}}",
    "Call `web_preview_context` first when preview state is unknown.",
    "Prefer `steps` over `script` for `web_preview_playwright`.",
    "Supported playwright step actions are: goto, click, dblclick, hover, fill, press, select, check, uncheck, waitForSelector, waitForTimeout, textContent, getAttribute, title, url, snapshot.",
    "If the tool reports that the preview is unavailable or blocked by bridge/cross-origin constraints, stop and explain the exact blocker to the user.",
  ].join("\n");
}

export function formatDocyrusWebBrowserToolResponsePrompt(
  response: IDocyrusWebBrowserToolResponsePrompt,
): string {
  return [
    "The docyrus-web-browser client tool returned a result.",
    "",
    `${DOCYRUS_WEB_BROWSER_RESULT_OPEN}`,
    JSON.stringify(response, null, 2),
    `${DOCYRUS_WEB_BROWSER_RESULT_CLOSE}`,
    "",
    "Continue the task using this result. If the tool reported an availability or bridge blocker, explain that blocker exactly and do not claim success.",
  ].join("\n");
}
