import type {
  AgentCapabilityKind,
  AgentDraftState,
  AgentInfo,
  AgentKnowledgeBinding,
  AgentToolBinding,
  AgentValidationIssue,
} from '../types';

import { computed, reactive } from 'vue';

import {
  buildInteractionConfigPayload,
  createEmptyInteractionConfig,
  normalizeInteractionConfig,
  validateInteractionConfig,
} from '../interaction-config';

const BASE_NODE_ID = 'agent-base';
const SAFE_TOOL_NAME_PATTERN = /^[\w-]+$/;

function createLocalId(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
}

function isSafeToolName(name?: string) {
  return SAFE_TOOL_NAME_PATTERN.test(String(name || ''));
}

function buildFallbackToolName(prefix: string, resource?: Record<string, any>) {
  const id = resource?.id ? String(resource.id) : createLocalId(prefix);
  return `${prefix}_${id}`;
}

function toolKindFromType(
  toolType?: string,
): Exclude<AgentCapabilityKind, 'knowledge'> {
  const normalized = String(toolType || '').toUpperCase();
  if (normalized === 'WORKFLOW') return 'workflow';
  if (normalized === 'MCP') return 'mcp';
  return 'plugin';
}

function resolveToolName(
  kind: Exclude<AgentCapabilityKind, 'knowledge'>,
  resource?: Record<string, any>,
) {
  if (isSafeToolName(resource?.englishName)) {
    return String(resource?.englishName);
  }
  if (isSafeToolName(resource?.name)) {
    return String(resource?.name);
  }
  return buildFallbackToolName(
    kind === 'workflow' ? 'workflow' : kind === 'mcp' ? 'mcp' : 'plugin',
    resource,
  );
}

function normalizeBindingToolName(binding: AgentToolBinding) {
  if (String(binding.toolType || '').toUpperCase() === 'MCP') {
    return '';
  }
  if (isSafeToolName(binding.toolName)) {
    return String(binding.toolName);
  }
  const kind = toolKindFromType(binding.toolType);
  const resource = {
    ...(binding.resourceSnapshot || {}),
    ...(binding.resourceSummary || {}),
    id:
      binding.targetId ||
      binding.resourceSummary?.id ||
      binding.resourceSnapshot?.id,
  };
  return resolveToolName(kind, resource);
}

export function createEmptyAgent(): AgentInfo {
  return {
    name: '未命名智能体',
    description: '',
    avatar: '',
    categoryId: '',
    modelId: '',
    promptConfigJson: { systemPrompt: '' },
    generationConfigJson: { stream: true },
    memoryConfigJson: {
      compressionParameter: {
        enabled: true,
        msgThreshold: 12,
        lastKeep: 8,
        minCompressionTokenThreshold: 6000,
      },
    },
    interactionConfigJson: createEmptyInteractionConfig(),
    status: 1,
  };
}

function normalizeAgent(agent?: AgentInfo): AgentInfo {
  const source = agent || {};
  const memoryConfig = source.memoryConfigJson || {};
  const compressionParameter = memoryConfig.compressionParameter || {};
  const defaultCompressionParameter =
    createEmptyAgent().memoryConfigJson?.compressionParameter || {};
  const legacyMsgThreshold = memoryConfig.maxAttachedMessageCount;
  return {
    ...createEmptyAgent(),
    ...source,
    promptConfigJson: {
      systemPrompt: '',
      ...source.promptConfigJson,
    },
    generationConfigJson: {
      ...source.generationConfigJson,
      stream: source.generationConfigJson?.stream !== false,
    },
    memoryConfigJson: {
      ...memoryConfig,
      compressionParameter: {
        enabled: true,
        ...compressionParameter,
        msgThreshold:
          compressionParameter.msgThreshold ??
          legacyMsgThreshold ??
          defaultCompressionParameter.msgThreshold,
        lastKeep:
          compressionParameter.lastKeep ?? defaultCompressionParameter.lastKeep,
        minCompressionTokenThreshold:
          compressionParameter.minCompressionTokenThreshold ??
          defaultCompressionParameter.minCompressionTokenThreshold,
      },
    },
    interactionConfigJson: normalizeInteractionConfig(
      source.interactionConfigJson,
    ),
  };
}

function normalizeKnowledgeBinding(
  binding: AgentKnowledgeBinding,
  index: number,
): AgentKnowledgeBinding {
  return {
    ...binding,
    enabled: binding.enabled !== false,
    localId:
      binding.localId || String(binding.id || createLocalId('knowledge')),
    optionsJson: {
      limit: 5,
      scoreThreshold: 0.5,
      ...binding.optionsJson,
    },
    retrievalMode: binding.retrievalMode || 'HYBRID',
    sortNo: binding.sortNo ?? index + 1,
  };
}

function normalizeToolBinding(
  binding: AgentToolBinding,
  index: number,
): AgentToolBinding {
  const optionsJson = {
    ...(binding.optionsJson || {}),
  };
  if (String(optionsJson.executionMode || '').toUpperCase() !== 'ASYNC') {
    optionsJson.executionMode = 'SYNC';
  }
  return {
    ...binding,
    enabled: binding.enabled !== false,
    hitlEnabled: Boolean(binding.hitlEnabled),
    localId:
      binding.localId ||
      String(
        binding.id ||
          createLocalId(String(binding.toolType || 'tool').toLowerCase()),
      ),
    toolName: normalizeBindingToolName(binding),
    optionsJson,
    sortNo: binding.sortNo ?? index + 1,
  };
}

export function useAgentDesignerState() {
  const state = reactive<AgentDraftState>({
    agent: createEmptyAgent(),
    knowledgeBindings: [],
    toolBindings: [],
    selectedNodeId: BASE_NODE_ID,
    panelMode: 'base',
    dirty: false,
  });

  const selectedCapability = computed(() => {
    if (state.selectedNodeId.startsWith('knowledge:')) {
      const localId = state.selectedNodeId.slice('knowledge:'.length);
      return {
        kind: 'knowledge' as AgentCapabilityKind,
        binding: state.knowledgeBindings.find(
          (item) => item.localId === localId,
        ),
      };
    }
    if (state.selectedNodeId.startsWith('tool:')) {
      const localId = state.selectedNodeId.slice('tool:'.length);
      const binding = state.toolBindings.find(
        (item) => item.localId === localId,
      );
      return {
        kind: toolKindFromType(binding?.toolType) as AgentCapabilityKind,
        binding,
      };
    }
    return undefined;
  });

  function markDirty() {
    state.dirty = true;
  }

  function reset(agent?: AgentInfo) {
    state.agent = normalizeAgent(agent);
    state.knowledgeBindings = (agent?.knowledgeBindings || []).map(
      (binding, index) => normalizeKnowledgeBinding(binding, index),
    );
    state.toolBindings = (agent?.toolBindings || []).map((binding, index) =>
      normalizeToolBinding(binding, index),
    );
    state.selectedNodeId = BASE_NODE_ID;
    state.panelMode = 'base';
    state.dirty = false;
  }

  function selectBase() {
    state.selectedNodeId = BASE_NODE_ID;
    state.panelMode = 'base';
  }

  function selectNode(nodeId: string) {
    state.selectedNodeId = nodeId;
    state.panelMode = nodeId === BASE_NODE_ID ? 'base' : 'capability';
  }

  function openTryout() {
    state.panelMode = 'tryout';
  }

  function addKnowledgeNode(resource?: Record<string, any>) {
    const binding = normalizeKnowledgeBinding(
      {
        knowledgeId: resource?.id ? String(resource.id) : '',
        resourceSummary: resource || {},
      },
      state.knowledgeBindings.length,
    );
    state.knowledgeBindings.push(binding);
    state.selectedNodeId = `knowledge:${binding.localId}`;
    state.panelMode = 'capability';
    markDirty();
  }

  function addToolNode(
    kind: Exclude<AgentCapabilityKind, 'knowledge'>,
    resource?: Record<string, any>,
  ) {
    const toolType =
      kind === 'workflow' ? 'WORKFLOW' : kind === 'mcp' ? 'MCP' : 'PLUGIN';
    const binding = normalizeToolBinding(
      {
        toolType,
        targetId: resource?.mcpId
          ? String(resource.mcpId)
          : resource?.id
            ? String(resource.id)
            : '',
        toolName: kind === 'mcp' ? '' : resolveToolName(kind, resource),
        resourceSummary: resource || {},
      },
      state.toolBindings.length,
    );
    state.toolBindings.push(binding);
    state.selectedNodeId = `tool:${binding.localId}`;
    state.panelMode = 'capability';
    markDirty();
  }

  function removeSelectedCapability() {
    const selected = selectedCapability.value;
    if (!selected?.binding?.localId) return;
    if (selected.kind === 'knowledge') {
      state.knowledgeBindings = state.knowledgeBindings.filter(
        (item) => item.localId !== selected.binding?.localId,
      );
    } else {
      state.toolBindings = state.toolBindings.filter(
        (item) => item.localId !== selected.binding?.localId,
      );
    }
    selectBase();
    markDirty();
  }

  function validate(): AgentValidationIssue[] {
    const issues: AgentValidationIssue[] = [];
    if (!String(state.agent.name || '').trim()) {
      issues.push({
        nodeId: BASE_NODE_ID,
        field: 'name',
        message: '请填写 Agent 名称',
      });
    }
    if (!state.agent.modelId) {
      issues.push({
        nodeId: BASE_NODE_ID,
        field: 'modelId',
        message: '请选择模型',
      });
    }
    issues.push(
      ...validateInteractionConfig(state.agent.interactionConfigJson),
    );
    state.knowledgeBindings.forEach((binding) => {
      if (!binding.knowledgeId) {
        issues.push({
          nodeId: `knowledge:${binding.localId}`,
          field: 'knowledgeId',
          message: '请选择知识库',
        });
      }
    });
    state.toolBindings.forEach((binding) => {
      const nodeId = `tool:${binding.localId}`;
      if (!binding.targetId) {
        issues.push({ nodeId, field: 'targetId', message: '请选择能力资源' });
      }
      if (String(binding.toolType || '').toUpperCase() === 'MCP') {
        return;
      }
      if (!String(binding.toolName || '').trim()) {
        issues.push({ nodeId, field: 'toolName', message: '请填写工具名称' });
      } else if (!isSafeToolName(binding.toolName)) {
        issues.push({
          nodeId,
          field: 'toolName',
          message: '工具名称只能包含英文、数字、下划线或中划线',
        });
      }
    });
    return issues;
  }

  function buildPayloadAgent(): AgentInfo {
    const memoryConfigJson = state.agent.memoryConfigJson || {};
    const compressionParameter = memoryConfigJson.compressionParameter || {};
    const { maxAttachedMessageCount, ...restMemoryConfigJson } =
      memoryConfigJson;
    return {
      ...state.agent,
      interactionConfigJson: buildInteractionConfigPayload(
        state.agent.interactionConfigJson,
      ),
      generationConfigJson: {
        ...state.agent.generationConfigJson,
        stream: state.agent.generationConfigJson?.stream !== false,
      },
      memoryConfigJson: {
        ...restMemoryConfigJson,
        compressionParameter: {
          ...compressionParameter,
          enabled: true,
        },
      },
      status: state.agent.status ?? 1,
    };
  }

  function buildKnowledgePayload(agentId?: number | string) {
    return state.knowledgeBindings.map((binding, index) => ({
      ...binding,
      agentId,
      enabled: binding.enabled !== false,
      sortNo: index + 1,
    }));
  }

  function buildToolPayload(agentId?: number | string) {
    return state.toolBindings.map((binding, index) => {
      const isMcp = String(binding.toolType || '').toUpperCase() === 'MCP';
      return {
        ...binding,
        agentId,
        enabled: binding.enabled !== false,
        hitlEnabled: Boolean(binding.hitlEnabled),
        toolName: isMcp ? '' : binding.toolName,
        sortNo: index + 1,
      };
    });
  }

  reset();

  return {
    BASE_NODE_ID,
    state,
    selectedCapability,
    addKnowledgeNode,
    addToolNode,
    buildKnowledgePayload,
    buildPayloadAgent,
    buildToolPayload,
    markDirty,
    openTryout,
    removeSelectedCapability,
    reset,
    selectBase,
    selectNode,
    validate,
  };
}
