// @ts-nocheck
/**
 * 플로우 연결 서비스
 */

import db from "../database/db";
import { FlowStepConnection, CreateFlowConnectionRequest } from "../types/flow";

export class FlowConnectionService {
  /**
   * 플로우 단계 연결 생성
   */
  async create(
    request: CreateFlowConnectionRequest
  ): Promise<FlowStepConnection> {
    // 순환 참조 체크
    if (
      await this.wouldCreateCycle(
        request.flowDefinitionId,
        request.fromStepId,
        request.toStepId
      )
    ) {
      throw new Error(
        "Creating this connection would create a cycle in the flow"
      );
    }

    const query = `
      INSERT INTO flow_step_connection (
        flow_definition_id, from_step_id, to_step_id, label
      )
      VALUES ($1, $2, $3, $4)
      RETURNING *
    `;

    const result = await db.query(query, [
      request.flowDefinitionId,
      request.fromStepId,
      request.toStepId,
      request.label || null,
    ]);

    return this.mapToFlowConnection(result[0]);
  }

  /**
   * 특정 플로우의 모든 연결 조회
   */
  async findByFlowId(flowDefinitionId: number): Promise<FlowStepConnection[]> {
    const query = `
      SELECT * FROM flow_step_connection 
      WHERE flow_definition_id = $1 
      ORDER BY id ASC
    `;

    const result = await db.query(query, [flowDefinitionId]);
    return result.map(this.mapToFlowConnection);
  }

  /**
   * 플로우 연결 단일 조회
   */
  async findById(id: number): Promise<FlowStepConnection | null> {
    const query = "SELECT * FROM flow_step_connection WHERE id = $1";
    const result = await db.query(query, [id]);

    if (result.length === 0) {
      return null;
    }

    return this.mapToFlowConnection(result[0]);
  }

  /**
   * 플로우 연결 삭제
   */
  async delete(id: number): Promise<boolean> {
    const query = "DELETE FROM flow_step_connection WHERE id = $1 RETURNING id";
    const result = await db.query(query, [id]);
    return result.length > 0;
  }

  /**
   * 특정 단계에서 나가는 연결 조회
   */
  async findOutgoingConnections(stepId: number): Promise<FlowStepConnection[]> {
    const query = `
      SELECT * FROM flow_step_connection 
      WHERE from_step_id = $1 
      ORDER BY id ASC
    `;

    const result = await db.query(query, [stepId]);
    return result.map(this.mapToFlowConnection);
  }

  /**
   * 특정 단계로 들어오는 연결 조회
   */
  async findIncomingConnections(stepId: number): Promise<FlowStepConnection[]> {
    const query = `
      SELECT * FROM flow_step_connection 
      WHERE to_step_id = $1 
      ORDER BY id ASC
    `;

    const result = await db.query(query, [stepId]);
    return result.map(this.mapToFlowConnection);
  }

  /**
   * 순환 참조 체크 (DFS)
   */
  private async wouldCreateCycle(
    flowDefinitionId: number,
    fromStepId: number,
    toStepId: number
  ): Promise<boolean> {
    // toStepId에서 출발해서 fromStepId에 도달할 수 있는지 확인
    const visited = new Set<number>();
    const stack = [toStepId];

    while (stack.length > 0) {
      const current = stack.pop()!;

      if (current === fromStepId) {
        return true; // 순환 발견
      }

      if (visited.has(current)) {
        continue;
      }

      visited.add(current);

      // 현재 노드에서 나가는 모든 연결 조회
      const query = `
        SELECT to_step_id 
        FROM flow_step_connection 
        WHERE flow_definition_id = $1 AND from_step_id = $2
      `;

      const result = await db.query(query, [flowDefinitionId, current]);

      for (const row of result) {
        stack.push(row.to_step_id);
      }
    }

    return false; // 순환 없음
  }

  /**
   * DB 행을 FlowStepConnection 객체로 변환
   */
  private mapToFlowConnection(row: any): FlowStepConnection {
    return {
      id: row.id,
      flowDefinitionId: row.flow_definition_id,
      fromStepId: row.from_step_id,
      toStepId: row.to_step_id,
      label: row.label,
      createdAt: row.created_at,
    };
  }
}
