import { escapeXml } from '@lobechat/prompts';
import debug from 'debug';

import { BaseFirstUserContentProvider } from '../base/BaseFirstUserContentProvider';
import type { PipelineContext, ProcessorOptions } from '../types';

declare module '../types' {
  interface PipelineContextMetadataOverrides {
    agentBuilderContextInjected?: boolean;
  }
}

const log = debug('context-engine:provider:AgentBuilderContextInjector');

const SYSTEM_ROLE_CONTEXT_PREVIEW_LENGTH = 10_000;

/**
 * Official tool item for Agent Builder context
 */
export interface OfficialToolItem {
  /** Tool description */
  description?: string;
  /** Whether the tool is enabled for current agent */
  enabled?: boolean;
  /** Tool identifier */
  identifier: string;
  /** Whether the tool is installed/connected */
  installed?: boolean;
  /** Tool display name */
  name: string;
  /** Tool type: 'builtin' for built-in tools, 'klavis' for LobeHub Mcp servers, 'lobehub-skill' for LobeHub Skill providers */
  type: 'builtin' | 'klavis' | 'lobehub-skill';
}

/**
 * Agent context for Agent Builder
 */
export interface AgentBuilderContext {
  /** Agent configuration */
  config?: {
    chatConfig?: Record<string, any>;
    model?: string;
    openingMessage?: string;
    openingQuestions?: string[];
    params?: Record<string, any>;
    plugins?: string[];
    provider?: string;
    systemRole?: string;
  };
  /** Agent metadata */
  meta?: {
    avatar?: string;
    backgroundColor?: string;
    description?: string;
    tags?: string[];
    title?: string;
  };
  /** Available official tools (builtin tools, Klavis integrations, and LobehubSkill providers) */
  officialTools?: OfficialToolItem[];
}

export interface AgentBuilderContextInjectorConfig {
  /** Agent context to inject */
  agentContext?: AgentBuilderContext;
  /** Whether Agent Builder is enabled */
  enabled?: boolean;
  /** Function to format agent context */
  formatAgentContext?: (context: AgentBuilderContext) => string;
}

/**
 * Format agent context as XML for injection
 */
const defaultFormatAgentContext = (context: AgentBuilderContext): string => {
  const parts: string[] = [];

  // Add meta section
  if (context.meta) {
    const metaFields: string[] = [];
    if (context.meta.title) metaFields.push(`  <title>${escapeXml(context.meta.title)}</title>`);
    if (context.meta.description)
      metaFields.push(`  <description>${escapeXml(context.meta.description)}</description>`);
    if (context.meta.avatar)
      metaFields.push(`  <avatar>${escapeXml(context.meta.avatar)}</avatar>`);
    if (context.meta.backgroundColor)
      metaFields.push(`  <backgroundColor>${context.meta.backgroundColor}</backgroundColor>`);
    if (context.meta.tags && context.meta.tags.length > 0)
      metaFields.push(`  <tags>${context.meta.tags.join(', ')}</tags>`);

    if (metaFields.length > 0) {
      parts.push(`<agent_meta>\n${metaFields.join('\n')}\n</agent_meta>`);
    }
  }

  // Add config section
  if (context.config) {
    const configFields: string[] = [];
    if (context.config.model)
      configFields.push(
        `  <model provider="${context.config.provider || 'unknown'}">${context.config.model}</model>`,
      );
    if (context.config.plugins && context.config.plugins.length > 0)
      configFields.push(
        `  <enabled_plugins>${context.config.plugins.join(', ')}</enabled_plugins>`,
      );
    if (context.config.openingMessage)
      configFields.push(
        `  <openingMessage>${escapeXml(context.config.openingMessage)}</openingMessage>`,
      );
    if (context.config.openingQuestions && context.config.openingQuestions.length > 0) {
      const questions = context.config.openingQuestions
        .map((q) => `    <question>${escapeXml(q)}</question>`)
        .join('\n');
      configFields.push(`  <openingQuestions>\n${questions}\n  </openingQuestions>`);
    }
    if (context.config.systemRole) {
      const systemRole =
        context.config.systemRole.length > SYSTEM_ROLE_CONTEXT_PREVIEW_LENGTH
          ? `${context.config.systemRole.slice(0, SYSTEM_ROLE_CONTEXT_PREVIEW_LENGTH)}...`
          : context.config.systemRole;

      configFields.push(
        `  <systemRole length="${context.config.systemRole.length}">${escapeXml(systemRole)}</systemRole>`,
      );
    }

    if (configFields.length > 0) {
      parts.push(`<agent_config>\n${configFields.join('\n')}\n</agent_config>`);
    }
  }

  // Add official tools section
  if (context.officialTools && context.officialTools.length > 0) {
    const builtinTools = context.officialTools.filter((t) => t.type === 'builtin');
    const klavisTools = context.officialTools.filter((t) => t.type === 'klavis');
    const lobehubSkillTools = context.officialTools.filter((t) => t.type === 'lobehub-skill');

    const toolsSections: string[] = [];

    if (builtinTools.length > 0) {
      const builtinItems = builtinTools
        .map((t) => {
          const attrs = [`id="${t.identifier}"`, `enabled="${t.enabled ? 'true' : 'false'}"`].join(
            ' ',
          );
          const desc = t.description ? ` - ${escapeXml(t.description)}` : '';
          return `    <tool ${attrs}>${escapeXml(t.name)}${desc}</tool>`;
        })
        .join('\n');
      toolsSections.push(`  <builtin_tools>\n${builtinItems}\n  </builtin_tools>`);
    }

    if (klavisTools.length > 0) {
      const klavisItems = klavisTools
        .map((t) => {
          const attrs = [
            `id="${t.identifier}"`,
            `installed="${t.installed ? 'true' : 'false'}"`,
            `enabled="${t.enabled ? 'true' : 'false'}"`,
          ].join(' ');
          const desc = t.description ? ` - ${escapeXml(t.description)}` : '';
          return `    <tool ${attrs}>${escapeXml(t.name)}${desc}</tool>`;
        })
        .join('\n');
      toolsSections.push(`  <klavis_tools>\n${klavisItems}\n  </klavis_tools>`);
    }

    if (lobehubSkillTools.length > 0) {
      const lobehubSkillItems = lobehubSkillTools
        .map((t) => {
          const attrs = [
            `id="${t.identifier}"`,
            `installed="${t.installed ? 'true' : 'false'}"`,
            `enabled="${t.enabled ? 'true' : 'false'}"`,
          ].join(' ');
          const desc = t.description ? ` - ${escapeXml(t.description)}` : '';
          return `    <tool ${attrs}>${escapeXml(t.name)}${desc}</tool>`;
        })
        .join('\n');
      toolsSections.push(`  <lobehub_skill_tools>\n${lobehubSkillItems}\n  </lobehub_skill_tools>`);
    }

    if (toolsSections.length > 0) {
      parts.push(
        `<available_official_tools>\n${toolsSections.join('\n')}\n</available_official_tools>`,
      );
    }
  }

  if (parts.length === 0) {
    return '';
  }

  return `<current_agent_context>
<instruction>This is the current agent's configuration context. Use this information when the user asks about or wants to modify agent settings. Use togglePlugin to enable/disable tools, or installPlugin to install new tools (including builtin tools, Klavis servers, and LobehubSkill providers).</instruction>
${parts.join('\n')}
</current_agent_context>`;
};

/**
 * Agent Builder Context Injector
 * Responsible for injecting current agent context when Agent Builder tool is enabled.
 *
 * Extends BaseFirstUserContentProvider so the injected XML is consolidated
 * into the shared `systemInjection` message together with other before-first-user
 * providers (UserMemory, Knowledge, AgentManagement, ...). This keeps Phase 3
 * ordering intact and preserves prefix-cache friendliness.
 */
export class AgentBuilderContextInjector extends BaseFirstUserContentProvider {
  readonly name = 'AgentBuilderContextInjector';

  constructor(
    private config: AgentBuilderContextInjectorConfig,
    options: ProcessorOptions = {},
  ) {
    super(options);
  }

  protected buildContent(_context: PipelineContext): string | null {
    if (!this.config.enabled) {
      log('Agent Builder not enabled, skipping injection');
      return null;
    }

    if (!this.config.agentContext) {
      log('No agent context provided, skipping injection');
      return null;
    }

    const formatFn = this.config.formatAgentContext || defaultFormatAgentContext;
    const formattedContent = formatFn(this.config.agentContext);

    if (!formattedContent) {
      log('No content to inject after formatting');
      return null;
    }

    log('Agent Builder context prepared');
    return formattedContent;
  }

  protected async doProcess(context: PipelineContext): Promise<PipelineContext> {
    const result = await super.doProcess(context);
    if (this.config.enabled && this.config.agentContext) {
      result.metadata.agentBuilderContextInjected = true;
    }
    return result;
  }
}
