/**
 * Prompt Builder — 8层分层注入系统
 * 纯函数实现，不依赖 Midway IoC，所有外部依赖通过参数传入
 */

import { SkillLoaderService } from '../service/skill_loader.js';
import {
  buildMemorySystemPrompt,
  type MemoryTypeInfo,
  getToolUseEnforcement,
  getModelGuidance,
  getToolBehaviorGuidance,
} from './prompt_guidance.js';
import { getToolNamesByToolsets, TOOLSET_DEFAULTS } from '../tools/catalog.js';
import type { LLMMessage } from '../plugins/plugin_entry.js';
import type { ChatAttachment } from '../gateway/protocol.js';

// ─── 类型定义 ───

export interface BuildSystemPromptParams {
  agentSystemPrompt: string;
  modelId: string;
  availableToolNames: string[];
  skills: string[];
  skillLoader: SkillLoaderService;
  memoryEnabled: boolean;
  memoryContext?: string;
  memoryTypes?: MemoryTypeInfo[];
  hasExistingMemory?: boolean;
  crewContext?: string;
  toolPromptHints?: Record<string, string>;
}

export interface PromptLayer {
  name: string;
  content: string;
}

export interface BuildResult {
  prompt: string;
  layers: PromptLayer[];
}

// ─── 工具名列表构建 ───

export interface CollectToolNamesOpts {
  memoryEnabled?: boolean;
  hasSkills?: boolean;
  crewRole?: 'master' | 'sub';
}

/**
 * 根据 agent 能力配置，构建可用工具名列表（从 catalog 动态查询）
 */
export function collectAvailableToolNames(opts: CollectToolNamesOpts): string[] {
  const toolsets: string[] = [...TOOLSET_DEFAULTS];
  if (opts.memoryEnabled) toolsets.push('memory');
  if (opts.hasSkills) toolsets.push('skill');
  if (opts.crewRole === 'master') toolsets.push('crew');
  return getToolNamesByToolsets(toolsets);
}

// ─── 8层分层组装 ───

/** 向 layers 数组追加非空层，返回内容（方便链式拼接） */
function pushLayer(layers: PromptLayer[], name: string, content: string): string {
  if (!content) return '';
  layers.push({ name, content });
  return content;
}

/**
 * 构建完整系统提示词（8层分层注入）
 *
 * Layer 1: Agent 身份
 * Layer 2: 工具使用纪律
 * Layer 3: 模型特定指导
 * Layer 4: 工具行为策略
 * Layer 5: Skill 索引
 * Layer 6: 记忆系统
 * Layer 7: Crew 编排上下文
 * Layer 8: 元信息
 */
export function buildSystemPrompt(params: BuildSystemPromptParams): BuildResult {
  const layers: PromptLayer[] = [];
  const parts: string[] = [];

  const push = (name: string, content: string) => {
    const c = pushLayer(layers, name, content);
    if (c) parts.push(c);
  };

  // Layer 1: Agent 身份
  push('Agent 身份', params.agentSystemPrompt);

  // Layer 1.5: 记忆行为指令
  if (params.memoryEnabled) {
    push('记忆行为', buildMemorySystemPrompt(params.memoryTypes, params.hasExistingMemory));
  }

  // Layer 2: 工具使用纪律（有工具时注入）
  if (params.availableToolNames.length > 0) {
    push('工具使用纪律', getToolUseEnforcement(params.availableToolNames));
  }

  // Layer 3: 模型特定指导
  push('模型特定指导', getModelGuidance(params.modelId));

  // Layer 4: 工具行为策略
  push('工具行为策略', getToolBehaviorGuidance(params.availableToolNames, params.toolPromptHints));

  // Layer 5: Skill 索引
  if (params.skills.length > 0) {
    push('Skill 索引', params.skillLoader.buildSkillsPrompt(params.skills, params.availableToolNames));
  }

  // Layer 6: (记忆系统已在 Layer 1.5 注入，Agent 自行调用 memory_recall 读取)

  // Layer 7: Crew 编排上下文
  if (params.crewContext) {
    push('Crew 编排上下文', params.crewContext);
  }

  // Layer 8: 元信息
  push('元信息', `\n---\n当前时间: ${new Date().toISOString()}\n模型: ${params.modelId}`);

  return { prompt: parts.join('\n\n'), layers };
}

// ─── LLM 消息构建（含附件注入）───

export interface UserMessageInput {
  content: string;
  metadata?: Record<string, unknown>;
}

/**
 * 构建发送给 LLM 的消息数组。
 * 若用户消息携带附件元数据，则在用户消息后追加附件提示消息。
 */
export function buildLLMMessages(
  systemPrompt: string,
  history: LLMMessage[],
  userMessage: UserMessageInput,
  toolNames?: string[],
): LLMMessage[] {
  const messages: LLMMessage[] = [
    { role: 'system', content: systemPrompt },
    ...history,
    { role: 'user', content: userMessage.content },
  ];

  if (userMessage.metadata?.attachments && (userMessage.metadata.attachments as unknown[]).length) {
    const attachments = userMessage.metadata.attachments as ChatAttachment[];
    const desc = attachments.map(a => {
      const typeLabel = ({ image: '图片', video: '视频', pdf: 'PDF', document: '文件', other: '文件' } as Record<string, string>)[a.type];
      return `- ${typeLabel}: ${a.name} (URL: ${a.url})`;
    }).join('\n');

    const hints: string[] = [];
    const names = new Set(toolNames ?? []);
    const hasVideo = attachments.some(a => a.type === 'video');
    const hasVehicleDamageSkill = systemPrompt.includes('skill name="vehicle-damage-inspection"');
    if (hasVideo && names.has('execute_skill') && hasVehicleDamageSkill) {
      const video = attachments.find(a => a.type === 'video');
      hints.push(`如需分析或检查车辆视频、环车视频、旧伤、损伤、划痕、凹陷，请优先使用 execute_skill，name 传 "vehicle-damage-inspection"，input.videoUrl 传 "${video?.url || '视频URL'}"`);
    }
    if (names.has('image_recognize')) {
      hints.push(hasVideo
        ? 'image_recognize 只用于图片，不要用它直接分析视频文件'
        : '如需分析图片内容，请使用 image_recognize 工具，传入图片 URL');
    }
    if (names.has('image_to_image')) {
      hints.push('如需基于图片生成新图片，请使用 image_to_image 工具，将图片 URL 作为 referenceImage 参数');
    }
    if (hints.length === 0) {
      hints.push('附件已上传，可在需要时引用其 URL');
    }

    messages.push({
      role: 'user',
      content: `[系统提示] 用户上传了以下附件：\n${desc}\n${hints.join('。')}。`,
    });
  }

  return messages;
}
