/**
 * 🔥 데이터플로우 실행 컨트롤러
 *
 * 버튼 제어에서 관계 실행 시 사용되는 컨트롤러
 */

import { Request, Response } from "express";
import { AuthenticatedRequest } from "../types/auth";
import { query } from "../database/db";
import logger from "../utils/logger";
import { TableManagementService } from "../services/tableManagementService";

/**
 * 데이터 액션 실행
 */
export async function executeDataAction(
  req: AuthenticatedRequest,
  res: Response
): Promise<void> {
  try {
    const { tableName, data, actionType, connection } = req.body;
    const companyCode = req.user?.companyCode || "*";

    logger.info(`데이터 액션 실행 시작: ${actionType} on ${tableName}`, {
      tableName,
      actionType,
      dataKeys: Object.keys(data),
      connection: connection?.name,
    });

    // 연결 정보에 따라 다른 데이터베이스에 저장
    let result;

    if (connection && connection.id !== 0) {
      // 외부 데이터베이스 연결
      result = await executeExternalDatabaseAction(
        tableName,
        data,
        actionType,
        connection
      );
    } else {
      // 메인 데이터베이스 (현재 시스템)
      result = await executeMainDatabaseAction(
        tableName,
        data,
        actionType,
        companyCode
      );
    }

    logger.info(`데이터 액션 실행 완료: ${actionType} on ${tableName}`, result);

    res.json({
      success: true,
      message: `데이터 액션 실행 완료: ${actionType}`,
      data: result,
    });
  } catch (error: any) {
    logger.error("데이터 액션 실행 실패:", error);
    res.status(500).json({
      success: false,
      message: `데이터 액션 실행 실패: ${error.message}`,
      errorCode: "DATA_ACTION_EXECUTION_ERROR",
    });
  }
}

/**
 * 메인 데이터베이스에서 데이터 액션 실행
 */
async function executeMainDatabaseAction(
  tableName: string,
  data: Record<string, any>,
  actionType: string,
  companyCode: string
): Promise<any> {
  try {
    // 회사 코드 추가
    const dataWithCompany = {
      ...data,
      company_code: companyCode,
    };

    // UNIQUE 제약조건 검증 (INSERT/UPDATE/UPSERT 전)
    if (["insert", "update", "upsert"].includes(actionType.toLowerCase())) {
      const tms = new TableManagementService();
      const uniqueViolations = await tms.validateUniqueConstraints(
        tableName,
        dataWithCompany,
        companyCode
      );
      if (uniqueViolations.length > 0) {
        throw new Error(`중복된 값이 존재합니다: ${uniqueViolations.join(", ")}`);
      }
    }

    switch (actionType.toLowerCase()) {
      case "insert":
        return await executeInsert(tableName, dataWithCompany);
      case "update":
        return await executeUpdate(tableName, dataWithCompany);
      case "upsert":
        return await executeUpsert(tableName, dataWithCompany);
      case "delete":
        return await executeDelete(tableName, dataWithCompany);
      default:
        throw new Error(`지원하지 않는 액션 타입: ${actionType}`);
    }
  } catch (error) {
    logger.error(`메인 DB 액션 실행 오류 (${actionType}):`, error);
    throw error;
  }
}

/**
 * 외부 데이터베이스에서 데이터 액션 실행
 */
async function executeExternalDatabaseAction(
  tableName: string,
  data: Record<string, any>,
  actionType: string,
  connection: any
): Promise<any> {
  try {
    logger.info(
      `외부 DB 액션 실행: ${connection.name} (${connection.host}:${connection.port})`
    );
    logger.info(`테이블: ${tableName}, 액션: ${actionType}`, data);

    // 🔥 실제 외부 DB 연결 및 실행 로직 구현
    const { MultiConnectionQueryService } = await import(
      "../services/multiConnectionQueryService"
    );
    const queryService = new MultiConnectionQueryService();

    let result;
    switch (actionType.toLowerCase()) {
      case "insert":
        result = await queryService.insertDataToConnection(
          connection.id,
          tableName,
          data
        );
        logger.info(`외부 DB INSERT 성공:`, result);
        break;
      case "update":
        // TODO: UPDATE 로직 구현 (조건 필요)
        throw new Error(
          "UPDATE 액션은 아직 지원되지 않습니다. 조건 설정이 필요합니다."
        );
      case "delete":
        // TODO: DELETE 로직 구현 (조건 필요)
        throw new Error(
          "DELETE 액션은 아직 지원되지 않습니다. 조건 설정이 필요합니다."
        );
      default:
        throw new Error(`지원하지 않는 액션 타입: ${actionType}`);
    }

    return {
      success: true,
      message: `외부 DB 액션 실행 완료: ${actionType} on ${tableName}`,
      connection: connection.name,
      data: result,
      affectedRows: 1,
    };
  } catch (error) {
    logger.error(`외부 DB 액션 실행 오류 (${actionType}):`, error);
    throw error;
  }
}

/**
 * INSERT 실행
 */
async function executeInsert(
  tableName: string,
  data: Record<string, any>
): Promise<any> {
  try {
    // 동적 테이블 접근을 위한 raw query 사용
    const columns = Object.keys(data).join(", ");
    const values = Object.values(data);
    const placeholders = values.map((_, index) => `$${index + 1}`).join(", ");

    const insertQuery = `INSERT INTO ${tableName} (${columns}) VALUES (${placeholders}) RETURNING *`;

    logger.info(`INSERT 쿼리 실행:`, { query: insertQuery, values });

    const result = await query<any>(insertQuery, values);

    return {
      success: true,
      action: "insert",
      tableName,
      data: result,
      affectedRows: result.length,
    };
  } catch (error) {
    logger.error(`INSERT 실행 오류:`, error);
    throw error;
  }
}

/**
 * UPDATE 실행
 */
async function executeUpdate(
  tableName: string,
  data: Record<string, any>
): Promise<any> {
  try {
    logger.info(`UPDATE 액션 시작:`, { tableName, receivedData: data });

    // 1. 테이블의 실제 기본키 조회
    const primaryKeyQuery = `
      SELECT a.attname as column_name
      FROM pg_index i
      JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
      WHERE i.indrelid = $1::regclass AND i.indisprimary
    `;

    const pkResult = await query<{ column_name: string }>(primaryKeyQuery, [
      tableName,
    ]);

    if (!pkResult || pkResult.length === 0) {
      throw new Error(`테이블 ${tableName}의 기본키를 찾을 수 없습니다`);
    }

    const primaryKeyColumn = pkResult[0].column_name;
    logger.info(`테이블 ${tableName}의 기본키:`, primaryKeyColumn);

    // 2. 기본키 값 추출
    const primaryKeyValue = data[primaryKeyColumn];

    if (!primaryKeyValue && primaryKeyValue !== 0) {
      logger.error(`UPDATE 실패: 기본키 값이 없음`, {
        primaryKeyColumn,
        receivedData: data,
        availableKeys: Object.keys(data),
      });
      throw new Error(
        `UPDATE를 위한 기본키 값이 필요합니다 (${primaryKeyColumn})`
      );
    }

    // 3. 업데이트할 데이터에서 기본키 제외
    const updateData = { ...data };
    delete updateData[primaryKeyColumn];

    logger.info(`UPDATE 데이터 준비:`, {
      primaryKeyColumn,
      primaryKeyValue,
      updateFields: Object.keys(updateData),
    });

    // 4. 동적 UPDATE 쿼리 생성
    const setClause = Object.keys(updateData)
      .map((key, index) => `${key} = $${index + 1}`)
      .join(", ");

    const values = Object.values(updateData);
    const updateQuery = `UPDATE ${tableName} SET ${setClause} WHERE ${primaryKeyColumn} = $${values.length + 1} RETURNING *`;

    logger.info(`UPDATE 쿼리 실행:`, {
      query: updateQuery,
      values: [...values, primaryKeyValue],
    });

    const result = await query<any>(updateQuery, [...values, primaryKeyValue]);

    logger.info(`UPDATE 성공:`, { affectedRows: result.length });

    return {
      success: true,
      action: "update",
      tableName,
      data: result,
      affectedRows: result.length,
    };
  } catch (error) {
    logger.error(`UPDATE 실행 오류:`, error);
    throw error;
  }
}

/**
 * UPSERT 실행
 */
async function executeUpsert(
  tableName: string,
  data: Record<string, any>
): Promise<any> {
  try {
    // 먼저 INSERT를 시도하고, 실패하면 UPDATE
    try {
      return await executeInsert(tableName, data);
    } catch (insertError) {
      // INSERT 실패 시 UPDATE 시도
      logger.info(`INSERT 실패, UPDATE 시도:`, insertError);
      return await executeUpdate(tableName, data);
    }
  } catch (error) {
    logger.error(`UPSERT 실행 오류:`, error);
    throw error;
  }
}

/**
 * DELETE 실행
 */
async function executeDelete(
  tableName: string,
  data: Record<string, any>
): Promise<any> {
  try {
    const { id } = data;

    if (!id) {
      throw new Error("DELETE를 위한 ID가 필요합니다");
    }

    const deleteQuery = `DELETE FROM ${tableName} WHERE id = $1 RETURNING *`;

    logger.info(`DELETE 쿼리 실행:`, { query: deleteQuery, values: [id] });

    const result = await query<any>(deleteQuery, [id]);

    return {
      success: true,
      action: "delete",
      tableName,
      data: result,
      affectedRows: result.length,
    };
  } catch (error) {
    logger.error(`DELETE 실행 오류:`, error);
    throw error;
  }
}
