import { RectNodeModel } from '@logicflow/core';
import { END_ID, END_NODE, START_ID } from '@/libs/logic-flow/constant';
import type { FlowNodeAnchor, FlowNodeConnectRuleResult, FlowNodeProperties } from './index';

export default class FlowNodeModel extends RectNodeModel<FlowNodeProperties> {
  override getTextStyle() {
    const style = super.getTextStyle();
    style.color = 'transparent';
    return style;
  }

  private isAllowConnected(source: FlowNodeModel, target: FlowNodeModel, sourceAnchor: FlowNodeAnchor, targetAnchor: FlowNodeAnchor, edgeID?: string): FlowNodeConnectRuleResult {
    // 自身节点禁止连接
    if (source === target) return { isAllPass: false, msg: `节点不能连接自身` };

    // 获取当前节点禁止直接连接
    const forbidDirectTarget = getProperties(source).forbidDirectTarget ?? [];
    if (forbidDirectTarget.includes(target.id))
      return {
        isAllPass: false,
        msg: `当前 [${source.text.value}] 节点不能直接连接 [${forbidDirectTarget.map((id) => this.graphModel.getNodeModelById(id)?.text.value).join(' | ')}] 节点`,
      };
    // 获取目标节点禁止直接连接
    const forbidDirectSource = getProperties(target).forbidDirectSource ?? [];
    if (forbidDirectSource.includes(source.id))
      return {
        isAllPass: false,
        msg: `目标 [${target.text.value}] 节点不能直接连接 [${forbidDirectSource.map((id) => this.graphModel.getNodeModelById(id)?.text.value).join(' | ')}] 节点`,
      };

    // 获取目标节点 forbidSource
    let forbidSource = getProperties(target).forbidSource ?? [];
    if (forbidSource.includes(source.id)) return { isAllPass: false, msg: `目标 [${target.text.value}] 节点不能在当前 [${source.text.value}] 节点之后` };

    // 获取当前节点的上游节点
    const visited = new Set([source.id, target.id]);
    const prev = [source.id];
    do {
      const sourceId = prev.shift()!;
      visited.add(sourceId);
      const directNodes = this.graphModel.getNodeIncomingNode(sourceId);
      for (const directNode of directNodes) {
        if (forbidSource.includes(directNode.id))
          return {
            isAllPass: false,
            msg: `当前 [${source.text.value}] 节点上流路径存在：[${directNode.text.value}] 节点不能在目标 [${target.text.value}] 节点之前`,
          };
        if (!visited.has(directNode.id)) prev.push(directNode.id);
      }
    } while (prev.length);

    // 获取目标节点的下游节点
    const next = [target.id];
    do {
      const targetId = next.shift()!;
      visited.add(targetId);
      const directNodes = this.graphModel.getNodeOutgoingNode(targetId);
      for (const directNode of directNodes) {
        forbidSource = (getProperties(directNode).forbidSource as string[]) ?? [];
        if (forbidSource.includes(source.id))
          return {
            isAllPass: false,
            msg: `目标 [${target.text.value}] 节点下流路径存在：[${directNode.text.value}] 节点不能在当前 [${source.text.value}] 节点之后`,
          };
        if (!visited.has(directNode.id)) next.push(directNode.id);
      }
    } while (next.length);

    return { isAllPass: true };
  }

  override isAllowConnectedAsTarget(...args: any[]): FlowNodeConnectRuleResult {
    // 当前节点是否开始
    if (this.id === START_ID)
      return {
        isAllPass: false,
        msg: `当前 [${this.text.value}] 为开始节点不允许输入`,
      };
    // 获取目标节点连接到的所有起始节点
    const directNodes = this.graphModel.getNodeIncomingNode(this.id);
    if (directNodes.length >= 1)
      return {
        isAllPass: false,
        msg: `目标 [${this.text.value}] 节点已存在 ${directNodes.length}个输入 (${directNodes.map((node) => node.text.value)})`,
      };

    // 获取目标节点 onlySource
    const onlySource = (getProperties(this).onlySource as string[]) ?? [];
    if (onlySource.length && !onlySource.includes(args[0].id))
      return {
        isAllPass: false,
        msg: `目标 [${this.text.value}] 节点仅允许 [${onlySource.map((id) => this.graphModel.getNodeModelById(id)?.text.value).join(' | ')}] 节点作为输入`,
      };

    return this.isAllowConnected(args[0], this, args[1], args[2], args[3]);
  }

  override isAllowConnectedAsSource(...args: any[]): FlowNodeConnectRuleResult {
    // 当前节点是否结束
    if (this.id === END_ID)
      return {
        isAllPass: false,
        msg: `当前 [${this.text.value}] 为结束节点不允许输出`,
      };
    // 获取当前节点所有的下一级节点
    const directNodes = this.graphModel.getNodeOutgoingNode(this.id).filter((node) => (node.type as string) !== END_NODE);
    if (directNodes.length >= 1 && args[0].type !== END_NODE)
      return {
        isAllPass: false,
        msg: `当前 [${this.text.value}] 节点已存在 ${directNodes.length}个输出 (${directNodes.map((node) => node.text.value)})`,
      };

    // 获取目标节点 onlyTarget
    const onlyTarget = (getProperties(this).onlyTarget as string[]) ?? [];
    if (onlyTarget.length && !onlyTarget.includes(args[0].id))
      return {
        isAllPass: false,
        msg: `当前 [${this.text.value}] 节点仅允许 [${onlyTarget.map((id) => this.graphModel.getNodeModelById(id)?.text.value).join(' | ')}] 节点作为输出`,
      };

    return this.isAllowConnected(this, args[0], args[1], args[2], args[3]);
  }
}

function getProperties(model: FlowNodeModel | { properties: FlowNodeProperties }) {
  try {
    return model instanceof FlowNodeModel ? model.getProperties() : model?.properties ?? {};
  } catch {
    return model?.properties ?? {};
  }
}