/**
 * 디지털 트윈 외부 DB (DO_DY) 연결 및 쿼리 테스트 스크립트
 * READ-ONLY: SELECT 쿼리만 실행
 */

import { Pool } from "pg";
import mysql from "mysql2/promise";
import { CredentialEncryption } from "../src/utils/credentialEncryption";

async function testDigitalTwinDb() {
  // 내부 DB 연결 (연결 정보 저장용)
  const internalPool = new Pool({
    host: process.env.DB_HOST || "localhost",
    port: parseInt(process.env.DB_PORT || "5432"),
    database: process.env.DB_NAME || "plm",
    user: process.env.DB_USER || "postgres",
    password: process.env.DB_PASSWORD || "ph0909!!",
  });

  const encryptionKey =
    process.env.ENCRYPTION_SECRET_KEY || "default-secret-key-for-development";
  const encryption = new CredentialEncryption(encryptionKey);

  try {
    console.log("🚀 디지털 트윈 외부 DB 연결 테스트 시작\n");

    // 디지털 트윈 외부 DB 연결 정보
    const digitalTwinConnection = {
      name: "디지털트윈_DO_DY",
      description: "디지털 트윈 후판(자재) 재고 정보 데이터베이스 (MariaDB)",
      dbType: "mysql", // MariaDB는 MySQL 프로토콜 사용
      host: "1.240.13.83",
      port: 4307,
      databaseName: "DO_DY",
      username: "root",
      password: "pohangms619!#",
      sslEnabled: false,
      isActive: true,
    };

    console.log("📝 연결 정보:");
    console.log(`  - 이름: ${digitalTwinConnection.name}`);
    console.log(`  - DB 타입: ${digitalTwinConnection.dbType}`);
    console.log(`  - 호스트: ${digitalTwinConnection.host}:${digitalTwinConnection.port}`);
    console.log(`  - 데이터베이스: ${digitalTwinConnection.databaseName}\n`);

    // 1. 외부 DB 직접 연결 테스트
    console.log("🔍 외부 DB 직접 연결 테스트 중...");
    
    const externalConnection = await mysql.createConnection({
      host: digitalTwinConnection.host,
      port: digitalTwinConnection.port,
      database: digitalTwinConnection.databaseName,
      user: digitalTwinConnection.username,
      password: digitalTwinConnection.password,
      connectTimeout: 10000,
    });

    console.log("✅ 외부 DB 연결 성공!\n");

    // 2. SELECT 쿼리 실행
    console.log("📊 WSTKKY 테이블 쿼리 실행 중...\n");
    
    const query = `
      SELECT
        SKUMKEY   -- 제품번호
      , SKUDESC   -- 자재명
      , SKUTHIC   -- 두께
      , SKUWIDT   -- 폭
      , SKULENG   -- 길이
      , SKUWEIG   -- 중량
      , STOTQTY   -- 수량
      , SUOMKEY   -- 단위
      FROM DO_DY.WSTKKY
      LIMIT 10
    `;

    const [rows] = await externalConnection.execute(query);

    console.log("✅ 쿼리 실행 성공!\n");
    console.log(`📦 조회된 데이터: ${Array.isArray(rows) ? rows.length : 0}건\n`);

    if (Array.isArray(rows) && rows.length > 0) {
      console.log("🔍 샘플 데이터 (첫 3건):\n");
      rows.slice(0, 3).forEach((row: any, index: number) => {
        console.log(`[${index + 1}]`);
        console.log(`  제품번호(SKUMKEY): ${row.SKUMKEY}`);
        console.log(`  자재명(SKUDESC): ${row.SKUDESC}`);
        console.log(`  두께(SKUTHIC): ${row.SKUTHIC}`);
        console.log(`  폭(SKUWIDT): ${row.SKUWIDT}`);
        console.log(`  길이(SKULENG): ${row.SKULENG}`);
        console.log(`  중량(SKUWEIG): ${row.SKUWEIG}`);
        console.log(`  수량(STOTQTY): ${row.STOTQTY}`);
        console.log(`  단위(SUOMKEY): ${row.SUOMKEY}\n`);
      });

      // 전체 데이터 JSON 출력
      console.log("📄 전체 데이터 (JSON):");
      console.log(JSON.stringify(rows, null, 2));
      console.log("\n");
    }

    await externalConnection.end();

    // 3. 내부 DB에 연결 정보 저장
    console.log("💾 내부 DB에 연결 정보 저장 중...");

    const encryptedPassword = encryption.encrypt(digitalTwinConnection.password);

    // 중복 체크
    const existingResult = await internalPool.query(
      "SELECT id FROM flow_external_db_connection WHERE name = $1",
      [digitalTwinConnection.name]
    );

    let connectionId: number;

    if (existingResult.rows.length > 0) {
      connectionId = existingResult.rows[0].id;
      console.log(`⚠️  이미 존재하는 연결 (ID: ${connectionId})`);

      // 기존 연결 업데이트
      await internalPool.query(
        `UPDATE flow_external_db_connection 
         SET description = $1,
             db_type = $2,
             host = $3,
             port = $4,
             database_name = $5,
             username = $6,
             password_encrypted = $7,
             ssl_enabled = $8,
             is_active = $9,
             updated_at = NOW(),
             updated_by = 'system'
         WHERE name = $10`,
        [
          digitalTwinConnection.description,
          digitalTwinConnection.dbType,
          digitalTwinConnection.host,
          digitalTwinConnection.port,
          digitalTwinConnection.databaseName,
          digitalTwinConnection.username,
          encryptedPassword,
          digitalTwinConnection.sslEnabled,
          digitalTwinConnection.isActive,
          digitalTwinConnection.name,
        ]
      );
      console.log(`✅ 연결 정보 업데이트 완료`);
    } else {
      // 새 연결 추가
      const result = await internalPool.query(
        `INSERT INTO flow_external_db_connection (
          name, 
          description, 
          db_type, 
          host, 
          port, 
          database_name, 
          username, 
          password_encrypted,
          ssl_enabled,
          is_active,
          created_by
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'system')
        RETURNING id`,
        [
          digitalTwinConnection.name,
          digitalTwinConnection.description,
          digitalTwinConnection.dbType,
          digitalTwinConnection.host,
          digitalTwinConnection.port,
          digitalTwinConnection.databaseName,
          digitalTwinConnection.username,
          encryptedPassword,
          digitalTwinConnection.sslEnabled,
          digitalTwinConnection.isActive,
        ]
      );
      connectionId = result.rows[0].id;
      console.log(`✅ 새 연결 추가 완료 (ID: ${connectionId})`);
    }

    console.log("\n✅ 모든 테스트 완료!");
    console.log(`\n📌 연결 ID: ${connectionId}`);
    console.log("   이 ID를 사용하여 플로우 관리나 제어 관리에서 외부 DB를 연동할 수 있습니다.");

  } catch (error: any) {
    console.error("\n❌ 오류 발생:", error.message);
    console.error("상세 정보:", error);
    throw error;
  } finally {
    await internalPool.end();
  }
}

// 스크립트 실행
testDigitalTwinDb()
  .then(() => {
    console.log("\n🎉 스크립트 완료");
    process.exit(0);
  })
  .catch((error) => {
    console.error("\n💥 스크립트 실패:", error);
    process.exit(1);
  });


