import { DynamicStructuredTool } from '@langchain/core/tools';
import { z } from 'zod';
import type { FastifyBaseLogger } from 'fastify';

const MAX_CONTENT_LENGTH = 50_000;

/**
 * Fetch Page Tool
 *
 * Fetches a URL and returns its content as text/markdown.
 * - PDFs are converted to text using pdf-parse
 * - HTML pages are scraped with cheerio
 * - Output is truncated to 50k characters
 */

export interface FetchPageToolConfig {
  logger: FastifyBaseLogger;
}

export function createFetchPageTool(config: FetchPageToolConfig): DynamicStructuredTool {
  const { logger } = config;

  return new DynamicStructuredTool({
    name: 'FetchPage',
    description: 'Fetch a web page or PDF and return its text content. PDFs are automatically converted to markdown. Use this after WebSearch or ArxivSearch to read the full content of a result.',
    schema: z.object({
      url: z.string().url().describe('The URL to fetch'),
    }),
    func: async ({ url }) => {
      logger.debug({ url }, 'Executing FetchPage tool');

      try {
        const response = await fetch(url, {
          headers: { 'User-Agent': 'Mozilla/5.0 (compatible; research-agent/1.0)' },
          signal: AbortSignal.timeout(30_000),
        });

        if (!response.ok) {
          return JSON.stringify({ error: `HTTP ${response.status}: ${response.statusText}`, url });
        }

        const contentType = response.headers.get('content-type') ?? '';
        const isPdf = contentType.includes('pdf') || url.toLowerCase().endsWith('.pdf');

        let content: string;

        if (isPdf) {
          const buffer = Buffer.from(await response.arrayBuffer());
          const { PDFParse } = await import('pdf-parse');
          const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
          const parser = new PDFParse({ data: arrayBuffer });
          const result = await parser.getText();
          content = result.text;
          logger.debug({ url, chars: content.length, pages: result.pages.length }, 'PDF text extracted');
        } else {
          const html = await response.text();
          const { load } = await import('cheerio');
          const $ = load(html);

          // Remove non-content elements
          $('script, style, nav, footer, header, aside, [role="navigation"]').remove();

          // Prefer article/main content
          const main = $('article, main, [role="main"]').first();
          content = (main.length ? main : $('body')).text().replace(/\s{3,}/g, '\n\n').trim();

          logger.debug({ url, chars: content.length }, 'HTML page scraped');
        }

        const truncated = content.length > MAX_CONTENT_LENGTH;
        const output = truncated ? content.slice(0, MAX_CONTENT_LENGTH) + '\n\n[content truncated]' : content;

        return JSON.stringify({ url, content: output, truncated });
      } catch (error) {
        logger.error({ error, url }, 'FetchPage tool failed');
        return JSON.stringify({ error: error instanceof Error ? error.message : String(error), url });
      }
    },
  });
}
