/**
 * Composite Suggestions — suggests combining multi-step patterns into single calls.
 */

import type { HintRule, HintContext } from '../hint-engine';

function lastToolWas(ctx: HintContext, name: string): boolean {
  return ctx.recentCalls.length > 0 && ctx.recentCalls[0].toolName === name;
}

function recentToolCount(ctx: HintContext, name: string): number {
  return ctx.recentCalls.filter(c => c.toolName === name).length;
}

/**
 * True when the most recent call's args carried a non-'none' `returnAfterState`.
 * Such calls already inlined a fresh page snapshot in their response, so any
 * "consider read_page" follow-up nag is noise — the agent has already
 * observed the page state. See issue #845.
 */
function lastCallCarriedSnapshot(ctx: HintContext): boolean {
  if (ctx.recentCalls.length === 0) return false;
  const ras = ctx.recentCalls[0].args?.returnAfterState;
  return ras === 'ax' || ras === 'dom';
}

export const compositeSuggestionRules: HintRule[] = [
  {
    name: 'find-then-click',
    priority: 200,
    maxSeverity: 'info',
    // Duplicated by interact tool description "When to use" block.
    redundant_with_description: true,
    match(ctx) {
      if (ctx.toolName !== 'computer' && ctx.toolName !== 'click') return null;
      if (!lastToolWas(ctx, 'find')) return null;
      return 'Hint: Use interact(action:"click", query:"...") to find+click in one call.';
    },
  },
  {
    name: 'multiple-form-input',
    priority: 201,
    maxSeverity: 'warning',
    // Duplicated by form_input description (fill_form is named as alternative).
    redundant_with_description: true,
    match(ctx) {
      if (ctx.toolName !== 'form_input') return null;
      if (recentToolCount(ctx, 'form_input') >= 1) {
        return 'Hint: Use fill_form({fields:{...}}) for multiple fields.';
      }
      return null;
    },
  },
  {
    name: 'navigate-then-click',
    priority: 202,
    maxSeverity: 'info',
    match(ctx) {
      if (ctx.toolName !== 'computer' && ctx.toolName !== 'click' && ctx.toolName !== 'interact') return null;
      if (!lastToolWas(ctx, 'navigate')) return null;
      // Don't match screenshot operations — handled by sequence-detection
      if (/screenshot/i.test(ctx.resultText)) return null;
      return 'Hint: Use interact with waitForMs parameter to handle loading delays.';
    },
  },
  {
    name: 'read-page-truncated',
    priority: 203,
    maxSeverity: 'info',
    match(ctx) {
      if (ctx.toolName !== 'read_page') return null;
      if (ctx.isError) return null;
      if (/truncat|too (long|large)|content cut|\.\.\.$/i.test(ctx.resultText)) {
        return 'Hint: Output was truncated. Use inspect(query) for targeted state checks, find(query) for element search, or read_page mode="dom" for compact output.';
      }
      return null;
    },
  },
  {
    name: 'contenteditable-click-hint',
    priority: 204, // After existing composite rules (200-203)
    maxSeverity: 'info',
    match(ctx) {
      if (ctx.toolName !== 'computer') return null;
      if (ctx.isError) return null;

      // Check if the hit info mentions contenteditable
      if (/contenteditable|lexical|prosemirror|tiptap|slate|editor/i.test(ctx.resultText)) {
        return (
          'Hint: Click inside a rich text editor (contenteditable). ' +
          'Editor frameworks may intercept click events. ' +
          'Prefer: (1) interact with text query, (2) javascript_tool for direct element.click(), ' +
          '(3) read_page mode="dom" to get backendNodeId then use computer ref parameter.'
        );
      }

      return null;
    },
  },
  {
    name: 'coordinate-click-after-read',
    priority: 205,
    maxSeverity: 'warning',
    match(ctx) {
      if (ctx.toolName !== 'computer') return null;
      if (ctx.isError) return null;
      // Check if this is a coordinate click (not ref-based)
      if (!/Clicked at \(\d/.test(ctx.resultText)) return null;
      // Check if the hit was not interactive
      if (/\[not interactive\]/.test(ctx.resultText)) {
        return (
          'Hint: Clicked a non-interactive element. Use interact with a text query ' +
          'or read_page mode="dom" to find the correct target.'
        );
      }
      return null;
    },
  },
  {
    name: 'state-check-after-action',
    priority: 206,
    maxSeverity: 'warning',
    // Duplicated by inspect description "When to use" + read_page "When NOT to use".
    redundant_with_description: true,
    match(ctx) {
      if (ctx.toolName !== 'read_page') return null;
      if (
        lastToolWas(ctx, 'navigate') ||
        lastToolWas(ctx, 'interact')
      ) {
        // Suppress when the previous action already returned a snapshot
        // via returnAfterState — the agent has already observed page state
        // in that response, so a follow-up read_page is the user's choice,
        // not something to nag about. See issue #845.
        if (lastCallCarriedSnapshot(ctx)) return null;
        return 'Hint: Use inspect(query) for quick page state checks after actions — e.g. inspect("error messages") or inspect("form field values").';
      }
      return null;
    },
  },
  {
    name: 'repeated-read-page',
    priority: 207,
    maxSeverity: 'warning',
    // Duplicated by read_page description "When NOT to use" naming inspect/find as alternatives.
    redundant_with_description: true,
    match(ctx) {
      if (ctx.toolName !== 'read_page') return null;
      if (recentToolCount(ctx, 'read_page') >= 2) {
        return 'Hint: Use inspect(query) for targeted extraction instead of repeated full page reads — e.g. inspect("what tabs are active") or inspect("visible errors").';
      }
      return null;
    },
  },
];
