import type {
  AgentStudioCanvasSize,
  AgentStudioEdgeView,
  AgentStudioLayoutSnapshot,
  AgentStudioNodeData,
  AgentStudioNodeView,
} from '../../components/agent-studio/types';
import type {
  AgentDraftState,
  AgentKnowledgeBinding,
  AgentOption,
  AgentToolBinding,
} from '../../types';

import { computed } from 'vue';

const BASE_NODE_ID = 'agent-base';
const BASE_POSITION = { x: 430, y: 260 };
const CAPABILITY_GAP = 104;
const CAPABILITY_OFFSET_X = 360;
const CAPABILITY_START_Y = 148;
const CAPABILITY_NODE_HEIGHT = 78;
const CAPABILITY_NODE_WIDTH = 212;
const LEFT_SCREEN_PADDING = 48;
const TOP_SCREEN_PADDING = 96;
const INSPECTOR_RESERVED_WIDTH = 468;
const MIN_VISIBLE_WORKSPACE_WIDTH = 520;

function firstText(...values: unknown[]) {
  const matched = values.find((value) => String(value || '').trim());
  return matched ? String(matched).trim() : '';
}

function buildKnowledgeTitle(
  binding: AgentKnowledgeBinding,
  options: AgentOption[],
) {
  const matchedOption = options.find(
    (item) => String(item.value) === String(binding.knowledgeId),
  );
  return firstText(
    binding.resourceSummary?.title,
    binding.resourceSummary?.name,
    binding.resourceSummary?.label,
    binding.resourceSummary?.displayName,
    binding.resourceSnapshot?.title,
    binding.resourceSnapshot?.name,
    binding.resourceSnapshot?.label,
    binding.resourceSnapshot?.displayName,
    binding.title,
    binding.name,
    binding.knowledgeName,
    binding.collectionName,
    matchedOption?.label,
    matchedOption?.raw?.title,
    matchedOption?.raw?.name,
  );
}

function findMatchedToolOption(
  binding: AgentToolBinding,
  options: AgentOption[],
) {
  const targetId = String(binding.targetId || '');
  if (!targetId) return undefined;
  return options.find((item) => {
    const raw = item.raw || {};
    return (
      String(item.value) === targetId ||
      String(raw.id || '') === targetId ||
      String(raw.mcpId || '') === targetId
    );
  });
}

function buildToolTitle(binding: AgentToolBinding, options: AgentOption[] = []) {
  const matchedOption = findMatchedToolOption(binding, options);
  return firstText(
    binding.resourceSummary?.title,
    binding.resourceSummary?.name,
    binding.resourceSummary?.label,
    binding.resourceSummary?.displayName,
    binding.resourceSummary?.mcpTitle,
    binding.resourceSnapshot?.title,
    binding.resourceSnapshot?.name,
    binding.resourceSnapshot?.label,
    binding.resourceSnapshot?.displayName,
    binding.resourceSnapshot?.mcpTitle,
    matchedOption?.label,
    matchedOption?.raw?.title,
    matchedOption?.raw?.name,
    matchedOption?.raw?.label,
    matchedOption?.raw?.displayName,
    matchedOption?.raw?.mcpTitle,
    binding.toolName,
  );
}

function buildToolDetail(
  binding: AgentToolBinding,
  fallback: string,
  options: AgentOption[] = [],
) {
  if (String(binding.toolType || '').toUpperCase() === 'MCP') {
    const matchedOption = findMatchedToolOption(binding, options);
    const resourceName = buildToolTitle(binding, options);
    const tools =
      binding.resourceSummary?.tools ||
      binding.resourceSnapshot?.tools ||
      matchedOption?.raw?.tools ||
      [];
    const toolCount = Array.isArray(tools) ? tools.length : 0;
    if (resourceName && toolCount > 0) {
      return `${resourceName} · ${toolCount} 个工具`;
    }
    return resourceName || fallback;
  }
  const toolName = firstText(binding.toolName);
  const resourceName = buildToolTitle(binding, options);
  if (toolName && resourceName && toolName !== resourceName) {
    return `${resourceName} / ${toolName}`;
  }
  return resourceName || toolName || fallback;
}

function toFlowPoint(
  point: { x: number; y: number },
  viewport: NonNullable<AgentStudioLayoutSnapshot['viewport']>,
) {
  return {
    x: (point.x - viewport.x) / viewport.zoom,
    y: (point.y - viewport.y) / viewport.zoom,
  };
}

function resolveVisibleLeftX(
  layout?: AgentStudioLayoutSnapshot,
  canvasSize?: AgentStudioCanvasSize,
) {
  const viewport = layout?.viewport;
  if (!viewport || !canvasSize?.width) {
    return BASE_POSITION.x - CAPABILITY_OFFSET_X;
  }

  const availableWidth = Math.max(
    MIN_VISIBLE_WORKSPACE_WIDTH,
    canvasSize.width - INSPECTOR_RESERVED_WIDTH,
  );
  const screenX = Math.min(
    LEFT_SCREEN_PADDING,
    Math.max(24, availableWidth - CAPABILITY_NODE_WIDTH - LEFT_SCREEN_PADDING),
  );
  return toFlowPoint({ x: screenX, y: 0 }, viewport).x;
}

function resolveVisibleTopY(
  layout?: AgentStudioLayoutSnapshot,
  canvasSize?: AgentStudioCanvasSize,
) {
  const viewport = layout?.viewport;
  if (!viewport || !canvasSize?.height) {
    return CAPABILITY_START_Y;
  }
  return toFlowPoint({ x: 0, y: TOP_SCREEN_PADDING }, viewport).y;
}

function hasVerticalOverlap(
  position: { x: number; y: number },
  occupied: Array<{ x: number; y: number }>,
) {
  return occupied.some(
    (item) =>
      Math.abs(item.x - position.x) < CAPABILITY_NODE_WIDTH &&
      Math.abs(item.y - position.y) < CAPABILITY_NODE_HEIGHT,
  );
}

export function resolveCapabilityNodePosition(params: {
  canvasSize?: AgentStudioCanvasSize;
  fallbackIndex: number;
  layout?: AgentStudioLayoutSnapshot;
  nodeId: string;
  occupiedPositions?: Array<{ x: number; y: number }>;
}) {
  const persisted = params.layout?.nodePositions?.[params.nodeId];
  if (persisted) return persisted;

  const occupied = params.occupiedPositions || [];
  const x = resolveVisibleLeftX(params.layout, params.canvasSize);
  let y =
    resolveVisibleTopY(params.layout, params.canvasSize) +
    params.fallbackIndex * CAPABILITY_GAP;

  while (hasVerticalOverlap({ x, y }, occupied)) {
    y += CAPABILITY_GAP;
  }

  return { x, y };
}

export function useAgentStudioModel(
  state: AgentDraftState,
  selectedNodeId: () => string,
  layout?: AgentStudioLayoutSnapshot,
  canvasSize?: () => AgentStudioCanvasSize | undefined,
  knowledgeOptions?: () => AgentOption[],
  toolOptions?: () => {
    mcp?: AgentOption[];
    plugin?: AgentOption[];
    workflow?: AgentOption[];
  },
) {
  return computed(() => {
    const positionOf = (nodeId: string, fallback: { x: number; y: number }) =>
      layout?.nodePositions?.[nodeId] || fallback;
    const size = canvasSize?.();
    const occupiedPositions: Array<{ x: number; y: number }> = Object.values(
      layout?.nodePositions || {},
    );
    const nodes: AgentStudioNodeView[] = [
      {
        id: BASE_NODE_ID,
        type: 'agentStudioBase',
        position: positionOf(BASE_NODE_ID, BASE_POSITION),
        width: 268,
        height: 104,
        data: {
          badge: '基座',
          detail: firstText(state.agent.description, '等待配置核心提示词'),
          iconKey: 'base',
          id: BASE_NODE_ID,
          kind: 'base',
          selected: selectedNodeId() === BASE_NODE_ID,
          title: firstText(state.agent.name, '未命名智能体'),
        } satisfies AgentStudioNodeData,
      },
    ];

    const knowledgeNodes = state.knowledgeBindings.map((binding, index) => {
      const nodeId = `knowledge:${binding.localId}`;
      const title = buildKnowledgeTitle(binding, knowledgeOptions?.() || []);
      const position = resolveCapabilityNodePosition({
        canvasSize: size,
        fallbackIndex: index,
        layout,
        nodeId,
        occupiedPositions,
      });
      occupiedPositions.push(position);
      return {
        id: nodeId,
        type: 'agentStudioCapability',
        position,
        width: CAPABILITY_NODE_WIDTH,
        height: CAPABILITY_NODE_HEIGHT,
        data: {
          badge: '知识库',
          detail: title || '待选择知识库',
          iconKey: 'knowledge',
          id: nodeId,
          kind: 'knowledge',
          selected: selectedNodeId() === nodeId,
          title: title || '知识库',
        } satisfies AgentStudioNodeData,
      };
    });
    const toolNodes = state.toolBindings.map((binding, index) => {
      const nodeId = `tool:${binding.localId}`;
      const toolType = String(binding.toolType || '').toUpperCase();
      const isWorkflow = toolType === 'WORKFLOW';
      const isMcp = toolType === 'MCP';
      const matchedOptions = isWorkflow
        ? toolOptions?.().workflow || []
        : isMcp
          ? toolOptions?.().mcp || []
          : toolOptions?.().plugin || [];
      const fallback = isWorkflow
        ? '待选择工作流'
        : isMcp
          ? '待选择 MCP'
          : '待选择插件工具';
      const detail = buildToolDetail(binding, fallback, matchedOptions);
      const position = resolveCapabilityNodePosition({
        canvasSize: size,
        fallbackIndex: state.knowledgeBindings.length + index,
        layout,
        nodeId,
        occupiedPositions,
      });
      occupiedPositions.push(position);
      return {
        id: nodeId,
        type: 'agentStudioCapability',
        position,
        width: CAPABILITY_NODE_WIDTH,
        height: CAPABILITY_NODE_HEIGHT,
        data: {
          badge: isWorkflow ? '工作流' : isMcp ? 'MCP' : '插件',
          detail,
          iconKey: isWorkflow ? 'workflow' : isMcp ? 'mcp' : 'plugin',
          id: nodeId,
          kind: isWorkflow ? 'workflow' : isMcp ? 'mcp' : 'plugin',
          selected: selectedNodeId() === nodeId,
          title:
            detail === fallback
              ? isWorkflow
                ? '工作流'
                : isMcp
                  ? 'MCP'
                  : '插件'
              : detail,
        } satisfies AgentStudioNodeData,
      };
    });

    const capabilityNodes = [...knowledgeNodes, ...toolNodes];

    const edges: AgentStudioEdgeView[] = capabilityNodes.map((node) => ({
      id: `edge:${node.id}`,
      source: BASE_NODE_ID,
      target: node.id,
    }));

    nodes.push(...capabilityNodes);
    return { edges, nodes };
  });
}
