import {
  IMPORT_STEP_KEYS,
  type ImportStageRequest,
  type ImportStepKey,
} from '../imports/imports.types';
import { permittedStepKeys } from '../imports/imports.access';
import { expandStageSheets } from '../imports/imports.mapping';
import type { AiChatServiceContext, AiSseEmitter, ModelToolCall } from './ai-chat.types';
import type { AgentToolContext } from './ai-chat.tools';
import { buildA2uiArtifact } from './ai-a2ui.artifact';
import { AiMessage } from './entities';
import { finishToolRun, startToolRun } from './ai-chat.tools';
import {
  isExcelAttachment,
  parseConfirmedMapping,
  parseConfirmedSettings,
} from './ai-chat.import-confirm';

function parseAttachmentArgs(
  parsedArgs: unknown,
): { parsedRecord: Record<string, unknown>; attachmentId: number } {
  const parsedRecord =
    parsedArgs && typeof parsedArgs === 'object' && !Array.isArray(parsedArgs)
      ? (parsedArgs as Record<string, unknown>)
      : {};
  if (
    typeof parsedRecord.attachmentId !== 'number' ||
    !Number.isInteger(parsedRecord.attachmentId) ||
    parsedRecord.attachmentId <= 0
  ) {
    throw new Error('缺少附件 attachmentId');
  }
  return { parsedRecord, attachmentId: parsedRecord.attachmentId };
}

async function beginImportToolRun(
  context: AiChatServiceContext,
  messageId: number,
  call: ModelToolCall,
  emit: AiSseEmitter,
  toolName: string,
) {
  return startToolRun(context, messageId, call, emit, {
    toolName,
    skillKey: null,
    argumentsData: null,
  });
}

interface ImportToolContext {
  run: Awaited<ReturnType<typeof beginImportToolRun>>['run'];
  parsedArgs: Awaited<ReturnType<typeof beginImportToolRun>>['parsedArgs'];
  startedAt: Awaited<ReturnType<typeof beginImportToolRun>>['startedAt'];
  assistant: AiMessage;
  agentContext: AgentToolContext;
  context: AiChatServiceContext;
  call: ModelToolCall;
  emit: AiSseEmitter;
  messageId: number;
}

async function runImportTool(
  context: AiChatServiceContext,
  messageId: number,
  call: ModelToolCall,
  agentContext: AgentToolContext,
  emit: AiSseEmitter,
  toolName: string,
  handler: (tool: ImportToolContext) => Promise<string>,
): Promise<string> {
  const { run, parsedArgs, startedAt } = await beginImportToolRun(
    context,
    messageId,
    call,
    emit,
    toolName,
  );
  try {
    const assistant = await context.messages.findOne({ where: { id: messageId } });
    if (!assistant) throw new Error('assistant message missing');
    return await handler({ run, parsedArgs, startedAt, assistant, agentContext, context, call, emit, messageId });
  } catch (error) {
    const summary = error instanceof Error ? error.message.slice(0, 100) : `${toolName} 失败`;
    await finishToolRun(context, run, call, startedAt, {
      status: 'failed',
      summary,
      error: summary,
    }, emit);
    return JSON.stringify({ status: 'failed', error: run.resultSummary });
  }
}

type ImportToolExecutor = (
  context: AiChatServiceContext,
  messageId: number,
  call: ModelToolCall,
  agentContext: AgentToolContext,
  emit: AiSseEmitter,
) => Promise<string>;

function makeImportToolExecutor(
  toolName: 'start_import_wizard',
  handler: (tool: ImportToolContext) => Promise<string>,
): ImportToolExecutor {
  return (context, messageId, call, agentContext, emit) =>
    runImportTool(context, messageId, call, agentContext, emit, toolName, handler);
}

export const executeStartImportWizard = makeImportToolExecutor(
  'start_import_wizard',
  async ({ run, parsedArgs, startedAt, assistant, agentContext: ac, context, call, emit, messageId }) => {
    const { parsedRecord, attachmentId } = parseAttachmentArgs(parsedArgs);
    const [attachment] = await context.attachmentService.requireReadyOwned(ac.userId, [
      attachmentId as number,
    ]);
    if (!isExcelAttachment(attachment)) throw new Error('附件不是 Excel 文件，无法生成导入向导');
    const stages = Array.isArray(parsedRecord.stages)
      ? (parsedRecord.stages as ImportStageRequest[])
      : [];
    if (stages.length === 0) throw new Error('缺少 stages 参数');
    for (const stage of stages) {
      if (!IMPORT_STEP_KEYS.includes(stage.stepKey)) {
        throw new Error(`stages 包含未知业务类型：${String(stage.stepKey)}`);
      }
      if (expandStageSheets(stage).length === 0) {
        throw new Error(`stages 中「${stage.stepKey}」缺少工作表 sheet/sheets，请指定 Excel 中对应的表名`);
      }
      if (
        stage.headerRow !== undefined &&
        (!Number.isInteger(stage.headerRow) || stage.headerRow < 1 || stage.headerRow > 1000)
      ) {
        throw new Error(`stages 中「${stage.stepKey}」的 headerRow 必须是 1-1000 之间的整数`);
      }
    }
    const mapping = parseConfirmedMapping(parsedRecord.mapping);
    const settings = parseConfirmedSettings(parsedRecord);
    if (!context.importsService) throw new Error('导入向导服务未配置');
    const buffer = await context.attachmentService.readStoredBuffer(attachment);
    const detail = await context.importsService.createRun(
      {
        id: ac.userId,
        permissions: [...ac.permissions],
        isSuperAdmin: ac.isSuperAdmin,
      },
      'ai',
      {
        originalName: attachment.originalName,
        mimeType: attachment.mimeType,
        size: attachment.size,
        buffer,
      },
      assistant.conversationId,
      stages,
      mapping,
      settings,
    );
    const wizard = compactImportWizard(detail);
    assistant.metadata = {
      ...assistant.metadata,
      a2uiImportWizard: wizard,
    };
    await context.messages.save(assistant);

    await finishToolRun(context, run, call, startedAt, {
      status: 'success',
      summary: `已生成导入向导：${detail.steps
        .filter((step) => step.status !== 'skipped')
        .map((step) => step.label)
        .join('、')}`,
    }, emit);
    emit('ui.import_wizard', { messageId, wizard });
    emit('ui.artifact', {
      messageId,
      artifact: buildA2uiArtifact({
        type: 'import_wizard',
        id: `wizard-${detail.id}`,
        status: 'pending',
        messageId,
        conversationId: assistant.conversationId,
        payload: wizard,
      }),
    });
    return JSON.stringify({
      status: 'success',
      runId: detail.id,
      steps: detail.steps
        .filter((step) => step.status !== 'skipped')
        .map((step) => ({ stepKey: step.stepKey, label: step.label, sheets: step.sheets })),
      permittedSteps: permittedStepKeys({
        id: ac.userId,
        permissions: [...ac.permissions],
        isSuperAdmin: ac.isSuperAdmin,
      }),
      message: '导入向导已生成，请提示用户打开向导，按阶段预览并确认后系统才会入库',
    });
  });

export function compactImportWizard(detail: any): {
  runId: string;
  fileName: string;
  sheets: Array<{
    name: string;
    suggestedStepKey: string | null;
    headers: string[];
    rowCount: number;
  }>;
  steps: Array<{ stepKey: string; label: string; sheets: string[]; status: string }>;
} {
  return {
    runId: detail.id,
    fileName: detail.fileName,
    sheets: detail.sheets.map((sheet: any) => ({
      name: sheet.name,
      suggestedStepKey: sheet.suggestedStepKey,
      headers: sheet.headers,
      rowCount: sheet.rowCount,
    })),
    steps: detail.steps.map((step: any) => ({
      stepKey: step.stepKey,
      label: step.label,
      sheets: step.sheets,
      status: step.status,
    })),
  };
}
