/**
 * Content Pipeline Plugin — processes tool results through the proxymodel stage pipeline.
 *
 * Extracts the content transformation logic from router.ts:
 * - maybeProcessContent (pipeline execution)
 * - Section drill-down (extractSectionParams, handleSectionDrillDown)
 * - sectionStore management
 *
 * This plugin handles:
 * 1. onToolCallBefore: intercept section drill-down requests (_resultId + _section params)
 * 2. onToolCallAfter: run tool results through the proxymodel pipeline
 */
import type { JsonRpcRequest, JsonRpcResponse } from '../../types.js';
import type { Section } from '../types.js';
import type { ProxyModelPlugin, PluginSessionContext } from '../plugin.js';

const SECTION_STORE_TTL_MS = 300_000; // 5 minutes

export function createContentPipelinePlugin(): ProxyModelPlugin {
  return {
    name: 'content-pipeline',
    description: 'Content transformation pipeline: paginate, section-split, summarize tool results.',

    async onToolCallBefore(_toolName, args, request, ctx) {
      // Intercept section drill-down requests
      const resultId = args['_resultId'] as string | undefined;
      const section = args['_section'] as string | undefined;

      if (resultId && section) {
        return handleSectionDrillDown(request, resultId, section, ctx);
      }

      return null;
    },

    async onPromptGet(_name, request, ctx) {
      // Intercept section drill-down on prompt results
      const args = (request.params as Record<string, unknown> | undefined)?.arguments as Record<string, unknown> | undefined;
      const resultId = args?.['_resultId'] as string | undefined;
      const section = args?.['_section'] as string | undefined;

      if (resultId && section) {
        return handleSectionDrillDown(request, resultId, section, ctx);
      }

      return null;
    },

    async onToolCallAfter(toolName, _args, response, ctx) {
      if (response.error) return response;

      // Extract text content from the response
      const raw = extractTextContent(response);
      if (!raw || raw.length <= 2000) return response;

      try {
        const result = await ctx.processContent(toolName, raw, 'toolResult');

        // If pipeline produced sections, store them for drill-down
        if (result.sections && result.sections.length > 0) {
          const resultId = `pm-${Date.now().toString(36)}`;
          storeSections(ctx, resultId, result.sections);

          const text = `${result.content}\n\n_resultId: ${resultId} — use _resultId and _section parameters to drill into a section.`;
          return {
            jsonrpc: '2.0',
            id: response.id,
            result: { content: [{ type: 'text', text }] },
          };
        }

        // Pipeline ran but no sections — return processed content if it changed
        if (result.content !== raw) {
          return {
            jsonrpc: '2.0',
            id: response.id,
            result: { content: [{ type: 'text', text: result.content }] },
          };
        }
      } catch {
        // Pipeline failed — return original response
      }

      return response;
    },
  };
}

/** Extract text content from a tool result response. */
function extractTextContent(response: JsonRpcResponse): string | null {
  if (!response.result || typeof response.result !== 'object') return null;
  const result = response.result as Record<string, unknown>;
  if (!Array.isArray(result['content'])) return null;
  const parts = result['content'] as Array<{ type: string; text?: string }>;
  const texts = parts.filter((p) => p.type === 'text' && p.text).map((p) => p.text!);
  return texts.length > 0 ? texts.join('\n') : null;
}

/** Handle section drill-down request. */
function handleSectionDrillDown(
  request: JsonRpcRequest,
  resultId: string,
  sectionId: string,
  ctx: PluginSessionContext,
): JsonRpcResponse {
  const sections = getSections(ctx, resultId);
  if (!sections) {
    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        content: [{
          type: 'text',
          text: 'Cached result not found (expired or invalid _resultId). Please re-call the tool without _resultId/_section to get a fresh result.',
        }],
      },
    };
  }

  const section = findSection(sections, sectionId);
  if (!section) {
    const available = sections.map((s) => s.id).join(', ');
    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        content: [{
          type: 'text',
          text: `Section '${sectionId}' not found. Available sections: ${available}`,
        }],
      },
    };
  }

  let text = section.content;
  if (section.children && section.children.length > 0) {
    const childToc = section.children.map((c) => `[${c.id}] ${c.title}`).join('\n');
    text += `\n\n${section.children.length} sub-sections:\n${childToc}\n\nUse _resultId="${resultId}" _section="<id>" to drill deeper.`;
  }

  return {
    jsonrpc: '2.0',
    id: request.id,
    result: { content: [{ type: 'text', text }] },
  };
}

/** Find a section by ID, searching recursively through children. */
function findSection(sections: Section[], id: string): Section | null {
  for (const section of sections) {
    if (section.id === id) return section;
    if (section.children) {
      const found = findSection(section.children, id);
      if (found) return found;
    }
  }
  return null;
}

// ── Section store using ctx.state ──

const SECTION_STORE_KEY = '_contentPipeline_sections';

interface SectionStoreEntry {
  sections: Section[];
  createdAt: number;
}

function storeSections(ctx: PluginSessionContext, resultId: string, sections: Section[]): void {
  let store = ctx.state.get(SECTION_STORE_KEY) as Map<string, SectionStoreEntry> | undefined;
  if (!store) {
    store = new Map();
    ctx.state.set(SECTION_STORE_KEY, store);
  }
  store.set(resultId, { sections, createdAt: Date.now() });

  // Evict stale entries
  const now = Date.now();
  for (const [key, entry] of store) {
    if (now - entry.createdAt > SECTION_STORE_TTL_MS) {
      store.delete(key);
    }
  }
}

function getSections(ctx: PluginSessionContext, resultId: string): Section[] | null {
  const store = ctx.state.get(SECTION_STORE_KEY) as Map<string, SectionStoreEntry> | undefined;
  if (!store) return null;
  const entry = store.get(resultId);
  if (!entry) return null;
  if (Date.now() - entry.createdAt > SECTION_STORE_TTL_MS) {
    store.delete(resultId);
    return null;
  }
  return entry.sections;
}
