import type { GraphNodeId, SceneGraphEdge, SceneGraphNode, SceneId } from '../types';

import { getConnectedComponent, getStorylineBucket } from './sceneGraphLineage';

function isCrossStorylineEdgeRejected(
  nodes: SceneGraphNode[],
  edges: SceneGraphEdge[],
  sourceGraphNodeId: GraphNodeId,
  targetGraphNodeId: GraphNodeId,
): boolean {
  const srcBucket = getStorylineBucket(nodes, edges, sourceGraphNodeId);
  const tgtBucket = getStorylineBucket(nodes, edges, targetGraphNodeId);

  // Запрет любых связей между основной (НАЧАЛО) и побочной (ПОБОЧНАЯ) линиями.
  if (srcBucket === 'main' && tgtBucket === 'side') return true;
  if (srcBucket === 'side' && tgtBucket === 'main') return true;

  // Разные побочные линии (разные компоненты).
  if (srcBucket === 'side' && tgtBucket === 'side') {
    const srcComp = getConnectedComponent(nodes, edges, sourceGraphNodeId);
    return !srcComp.has(targetGraphNodeId);
  }

  return false;
}

/**
 * true — связь добавлять нельзя: нет узлов, петля по одной сцене, то же ребро уже есть,
 * или с этого узла уже ведёт связь к другой карточке той же целевой сцены.
 * Разрешены несколько исходящих «вариантов» с одной ноды только на разные сцены.
 * Запрещены связи между основной и побочной линиями, а также между разными побочными линиями.
 */
export function isSceneGraphEdgeRejected(
  sceneGraphNodes: SceneGraphNode[],
  sceneGraphEdges: SceneGraphEdge[],
  sourceGraphNodeId: GraphNodeId,
  targetGraphNodeId: GraphNodeId,
): boolean {
  const gnScene = new Map<GraphNodeId, SceneId>(sceneGraphNodes.map((n) => [n.id, n.sceneId]));
  const srcScene = gnScene.get(sourceGraphNodeId);
  const tgtScene = gnScene.get(targetGraphNodeId);
  if (srcScene === undefined || tgtScene === undefined) return true;
  if (srcScene === tgtScene) return true;

  if (isCrossStorylineEdgeRejected(sceneGraphNodes, sceneGraphEdges, sourceGraphNodeId, targetGraphNodeId)) {
    return true;
  }

  for (const e of sceneGraphEdges) {
    if (e.sourceGraphNodeId !== sourceGraphNodeId) continue;
    if (e.targetGraphNodeId === targetGraphNodeId) return true;
    if (gnScene.get(e.targetGraphNodeId) === tgtScene) return true;
  }
  return false;
}
