/**
 * Read tool — read files from the filesystem with line numbers.
 */

import { readFileSync, statSync } from 'fs';
import { extname, resolve, normalize } from 'path';

const MAX_LINES = 2000;
const MAX_LINE_LENGTH = 2000;
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.svg']);

export const definition = {
  name: 'Read',
  description: 'Read a file from the filesystem. Returns content with line numbers. Supports text files and reports metadata for images.',
  input_schema: {
    type: 'object',
    properties: {
      file_path: { type: 'string', description: 'Absolute path to the file to read' },
      offset: { type: 'number', description: 'Line number to start reading from (1-based)' },
      limit: { type: 'number', description: 'Number of lines to read' }
    },
    required: ['file_path']
  }
};

/**
 * Check if a path is within one of the allowed directories.
 */
export function isAllowedPath(filePath, workspaceRoot, agentRoot) {
  const resolved = resolve(normalize(filePath));
  const wsNorm = resolve(normalize(workspaceRoot));
  const agNorm = resolve(normalize(agentRoot));
  return resolved.startsWith(wsNorm) || resolved.startsWith(agNorm);
}

export async function execute(input, context) {
  const { file_path, offset, limit } = input;

  if (!file_path) return { content: 'Error: file_path is required', is_error: true };

  const resolved = resolve(normalize(file_path));

  if (!isAllowedPath(resolved, context.workspaceRoot, context.agentRoot)) {
    return { content: `Error: Path "${resolved}" is outside allowed directories`, is_error: true };
  }

  try {
    const stats = statSync(resolved);
    const ext = extname(resolved).toLowerCase();

    if (IMAGE_EXTENSIONS.has(ext)) {
      return {
        content: `[Image file: ${resolved}. Size: ${stats.size} bytes. Type: ${ext}]`,
        is_error: false
      };
    }

    const raw = readFileSync(resolved, 'utf-8');
    const allLines = raw.split('\n');
    const totalLines = allLines.length;

    const startLine = Math.max(1, offset || 1);
    const maxLines = limit || MAX_LINES;
    const startIndex = startLine - 1;
    const endIndex = Math.min(startIndex + maxLines, totalLines);
    const lines = allLines.slice(startIndex, endIndex);

    const lineNumWidth = String(endIndex).length;
    const formatted = lines.map((line, i) => {
      const num = String(startIndex + i + 1).padStart(lineNumWidth, ' ');
      const truncated = line.length > MAX_LINE_LENGTH ? line.slice(0, MAX_LINE_LENGTH) + '...' : line;
      return `${num}\t${truncated}`;
    }).join('\n');

    // Track read timestamp for Write/Edit safety
    if (context.readFileTimestamps) {
      context.readFileTimestamps[resolved] = Date.now();
    }

    let result = formatted;
    if (endIndex < totalLines) {
      result += `\n\n[Showing lines ${startLine}-${endIndex} of ${totalLines}. Use offset/limit to read more.]`;
    }

    return { content: result, is_error: false };
  } catch (err) {
    if (err.code === 'ENOENT') {
      return { content: `Error: File not found: ${resolved}`, is_error: true };
    }
    return { content: `Error reading file: ${err.message}`, is_error: true };
  }
}
