/**
 * Tool Override Example - Demonstrates overriding built-in tools
 *
 * Extensions can register tools with the same name as built-in tools to replace them.
 * This is useful for:
 * - Adding logging or auditing to tool calls
 * - Implementing access control or sandboxing
 * - Routing tool calls to remote systems (e.g., shortcut-ssh-remote)
 * - Modifying tool behavior for specific workflows
 *
 * This example overrides the `read` tool to:
 * 1. Log all file access to a log file
 * 2. Block access to sensitive paths (e.g., .env files)
 * 3. Delegate to the original read implementation for allowed files
 *
 * Since no custom renderCall/renderResult are provided, the built-in renderer
 * is used automatically (syntax highlighting, line numbers, truncation warnings).
 *
 * Usage:
 *   shortcut -e ./tool-override.ts
 */

import { Type } from '@sinclair/typebox';
import { appendFileSync, constants, readFileSync } from 'fs';
import { access, readFile } from 'fs/promises';
import { homedir } from 'os';
import { join, resolve } from 'path';
import type { ExtensionAPI, TextContent } from 'shortcutxl/app';

const LOG_FILE = join(homedir(), '.shortcut', 'agent', 'read-access.log');

// Paths that are blocked from reading
const BLOCKED_PATTERNS = [
  /\.env$/,
  /\.env\..+$/,
  /secrets?\.(json|yaml|yml|toml)$/i,
  /credentials?\.(json|yaml|yml|toml)$/i,
  /\/\.ssh\//,
  /\/\.aws\//,
  /\/\.gnupg\//
];

function isBlockedPath(path: string): boolean {
  return BLOCKED_PATTERNS.some((pattern) => pattern.test(path));
}

function logAccess(path: string, allowed: boolean, reason?: string) {
  const timestamp = new Date().toISOString();
  const status = allowed ? 'ALLOWED' : 'BLOCKED';
  const msg = reason ? ` (${reason})` : '';
  const line = `[${timestamp}] ${status}: ${path}${msg}\n`;

  try {
    appendFileSync(LOG_FILE, line);
  } catch {
    // Ignore logging errors
  }
}

const readSchema = Type.Object({
  path: Type.String({ description: 'Path to the file to read (relative or absolute)' }),
  offset: Type.Optional(
    Type.Number({ description: 'Line number to start reading from (1-indexed)' })
  ),
  limit: Type.Optional(Type.Number({ description: 'Maximum number of lines to read' }))
});

export default function (shortcut: ExtensionAPI) {
  shortcut.registerTool({
    name: 'read', // Same name as built-in - this will override it
    label: 'read (audited)',
    description:
      'Read the contents of a file with access logging. Some sensitive paths (.env, secrets, credentials) are blocked.',
    parameters: readSchema,

    async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
      const { path, offset, limit } = params;
      const absolutePath = resolve(ctx.cwd, path);

      // Check if path is blocked
      if (isBlockedPath(absolutePath)) {
        logAccess(absolutePath, false, 'matches blocked pattern');
        return {
          content: [
            {
              type: 'text',
              text: `Access denied: "${path}" matches a blocked pattern (sensitive file). This tool blocks access to .env files, secrets, credentials, and SSH/AWS/GPG directories.`
            }
          ],
          details: { blocked: true }
        };
      }

      // Log allowed access
      logAccess(absolutePath, true);

      // Perform the actual read (simplified implementation)
      try {
        await access(absolutePath, constants.R_OK);
        const content = await readFile(absolutePath, 'utf-8');
        const lines = content.split('\n');

        // Apply offset and limit
        const startLine = offset ? Math.max(0, offset - 1) : 0;
        const endLine = limit ? startLine + limit : lines.length;
        const selectedLines = lines.slice(startLine, endLine);

        // Basic truncation (50KB limit)
        let text = selectedLines.join('\n');
        const maxBytes = 50 * 1024;
        if (Buffer.byteLength(text, 'utf-8') > maxBytes) {
          text = `${text.slice(0, maxBytes)}\n\n[Output truncated at 50KB]`;
        }

        return {
          content: [{ type: 'text', text }] as TextContent[],
          details: { lines: lines.length }
        };
      } catch (error: any) {
        return {
          content: [
            { type: 'text', text: `Error reading file: ${error.message}` }
          ] as TextContent[],
          details: { error: true }
        };
      }
    }

    // No renderCall/renderResult - uses built-in renderer automatically
    // (syntax highlighting, line numbers, truncation warnings, etc.)
  });

  // Also register a command to view the access log
  shortcut.registerCommand('read-log', {
    description: 'View the file access log',
    handler: async (_args, ctx) => {
      try {
        const log = readFileSync(LOG_FILE, 'utf-8');
        const lines = log.trim().split('\n').slice(-20); // Last 20 entries
        ctx.ui.notify(`Recent file access:\n${lines.join('\n')}`, 'info');
      } catch {
        ctx.ui.notify('No access log found', 'info');
      }
    }
  });
}
