#!/usr/bin/env php
<?php
/**
 * ptyMysqlOverwrite
 *
 * MySQL 테이블을 다른 서버/DB로 복사하는 도구
 * ptyMysqlBackup.php와 ptyMysqlRestore.php를 내부적으로 사용
 *
 * 설정 파일: ~/.ptyMysqlConfig.ini
 *
 * Usage: ./ptyMysqlOverwrite --src-mysql=섹션 --dst-mysql=섹션 --src-db=DB --dst-db=DB --src-table=테이블 --dst-table=테이블
 */

namespace platyFramework;

require_once __DIR__ . '/ptyLibrary_PHP/cli/ptyCliOptionParser.php';
require_once __DIR__ . '/ptyLibrary_PHP/cli/ptyCliLog.php';

// 인자 파싱
$parsed = ptyCliOptionParser::parse($argv);
$options = $parsed['options'];

$srcMysql = $options['src-mysql'] ?? null;
$dstMysql = $options['dst-mysql'] ?? null;
$srcDb = $options['src-db'] ?? null;
$dstDb = $options['dst-db'] ?? null;
$srcTable = $options['src-table'] ?? null;
$dstTable = $options['dst-table'] ?? null;
$verbose = isset($options['verbose']);
$force = isset($options['force']);

// 도움말 또는 필수 인자 확인
if (!$srcMysql || !$dstMysql || !$srcDb || !$dstDb || !$srcTable || !$dstTable || isset($options['help'])) {
    echo "사용법: {$argv[0]} [옵션]\n";
    echo "\n";
    echo "필수 옵션:\n";
    echo "  --src-mysql=섹션명    소스 MySQL INI 섹션\n";
    echo "  --dst-mysql=섹션명    대상 MySQL INI 섹션\n";
    echo "  --src-db=DB명         소스 데이터베이스명\n";
    echo "  --dst-db=DB명         대상 데이터베이스명\n";
    echo "  --src-table=테이블명  소스 테이블명\n";
    echo "  --dst-table=테이블명  대상 테이블명\n";
    echo "\n";
    echo "선택 옵션:\n";
    echo "  --force               확인 없이 바로 실행\n";
    echo "  --verbose             상세 로그 출력\n";
    echo "  --help                도움말 출력\n";
    echo "\n";
    echo "예시:\n";
    echo "  {$argv[0]} --src-mysql=api --dst-mysql=dev \\\n";
    echo "             --src-db=lawtice_db --dst-db=lawtice_dev \\\n";
    echo "             --src-table=new_law_items --dst-table=new_law_items\n";
    echo "\n";
    echo "  # 같은 서버 내에서 다른 DB로 복사\n";
    echo "  {$argv[0]} --src-mysql=default --dst-mysql=default \\\n";
    echo "             --src-db=prod_db --dst-db=dev_db \\\n";
    echo "             --src-table=users --dst-table=users\n";
    echo "\n";
    echo "설정 파일: ~/.ptyMysqlConfig.ini\n";
    echo "\n";
    echo "[api]\n";
    echo "host=api.example.com\n";
    echo "username=root\n";
    echo "password=\"password\"\n";
    echo "database=default_db\n";
    echo "\n";
    echo "[dev]\n";
    echo "host=dev.example.com\n";
    echo "username=root\n";
    echo "password=\"password\"\n";
    echo "database=default_db\n";
    echo "\n";
    exit(isset($options['help']) ? 0 : 1);
}

// ANSI 색상 코드
$RED = "\033[1;31m";
$GREEN = "\033[1;32m";
$YELLOW = "\033[1;33m";
$CYAN = "\033[1;36m";
$MAGENTA = "\033[1;35m";
$RESET = "\033[0m";

$log = new ptyCliLog(prefix: "OVERWRITE", color: ptyCliLog::COLOR_CYAN);

// 스크립트 경로
$scriptDir = __DIR__;
$backupScript = $scriptDir . '/ptyMysqlBackup.php';
$restoreScript = $scriptDir . '/ptyMysqlRestore.php';

// 스크립트 존재 확인
if (!file_exists($backupScript)) {
    $log->error("ptyMysqlBackup.php를 찾을 수 없습니다: $backupScript");
    exit(1);
}
if (!file_exists($restoreScript)) {
    $log->error("ptyMysqlRestore.php를 찾을 수 없습니다: $restoreScript");
    exit(1);
}

// 작업 정보 표시
echo "\n";
echo "{$CYAN}╔══════════════════════════════════════════════════════════════════╗{$RESET}\n";
echo "{$CYAN}║                  MySQL 테이블 Overwrite                          ║{$RESET}\n";
echo "{$CYAN}╚══════════════════════════════════════════════════════════════════╝{$RESET}\n";
echo "\n";

echo "{$YELLOW}[ 소스 ]{$RESET}\n";
echo str_repeat("-", 50) . "\n";
echo "  MySQL Section : $srcMysql\n";
echo "  Database      : $srcDb\n";
echo "  Table         : $srcTable\n";
echo "\n";

echo "{$YELLOW}[ 대상 ]{$RESET}\n";
echo str_repeat("-", 50) . "\n";
echo "  MySQL Section : $dstMysql\n";
echo "  Database      : $dstDb\n";
echo "  Table         : $dstTable\n";
echo "\n";

echo "{$RED}╔══════════════════════════════════════════════════════════════════╗{$RESET}\n";
echo "{$RED}║  주의: 대상 테이블의 기존 데이터가 완전히 삭제됩니다!            ║{$RESET}\n";
echo "{$RED}╚══════════════════════════════════════════════════════════════════╝{$RESET}\n";
echo "\n";

// 확인 절차
if (!$force) {
    echo "진행하시겠습니까? (y/N): ";
    $handle = fopen("php://stdin", "r");
    $line = fgets($handle);
    fclose($handle);

    $answer = strtolower(trim($line));
    if ($answer !== 'y' && $answer !== 'yes') {
        echo "\n작업이 취소되었습니다.\n";
        exit(0);
    }
    echo "\n";
}

// 임시 디렉토리 생성
$tempDir = sys_get_temp_dir() . '/ptyMysqlOverwrite_' . getmypid() . '_' . time();
if (!mkdir($tempDir, 0755, true)) {
    $log->error("임시 디렉토리 생성 실패: $tempDir");
    exit(1);
}
$log->info("임시 디렉토리: $tempDir");

// 정리 함수
function cleanup($tempDir) {
    if (is_dir($tempDir)) {
        $files = glob($tempDir . '/*');
        foreach ($files as $file) {
            if (is_file($file)) {
                unlink($file);
            }
        }
        rmdir($tempDir);
    }
}

// 에러 시 정리
register_shutdown_function(function() use ($tempDir) {
    cleanup($tempDir);
});

try {
    // ============================================
    // Step 1: 소스 테이블 백업
    // ============================================
    $log->info("=== Step 1: 소스 테이블 백업 ===");

    $backupCmd = "php " . escapeshellarg($backupScript);
    $backupCmd .= " " . escapeshellarg($srcDb);
    $backupCmd .= " " . escapeshellarg($srcTable);
    $backupCmd .= " --mysql=" . escapeshellarg($srcMysql);
    $backupCmd .= " --output=" . escapeshellarg($tempDir);
    if ($verbose) {
        $backupCmd .= " --verbose";
    }
    $backupCmd .= " 2>&1";

    // 실행 명령어 로그
    $log->info("실행: ./ptyMysqlBackup {$srcDb} {$srcTable} --mysql={$srcMysql} --output={$tempDir}");

    $output = [];
    exec($backupCmd, $output, $returnCode);

    if ($verbose) {
        foreach ($output as $line) {
            echo "  $line\n";
        }
    }

    if ($returnCode !== 0) {
        $log->error("백업 실패 (exit code: $returnCode)");
        foreach ($output as $line) {
            echo "  $line\n";
        }
        exit(1);
    }

    // 백업 파일 확인
    $srcBackupFile = $tempDir . "/{$srcDb}.{$srcTable}.sql";
    if (!file_exists($srcBackupFile)) {
        $log->error("백업 파일을 찾을 수 없습니다: $srcBackupFile");
        exit(1);
    }

    $backupSize = filesize($srcBackupFile);
    $log->success("백업 완료: " . formatBytes($backupSize));

    // ============================================
    // Step 2: 테이블명 변환 (src-table → dst-table)
    // ============================================
    //
    // mysqldump로 생성된 SQL 파일에는 원본 테이블명이 하드코딩되어 있습니다.
    // --src-table과 --dst-table이 다를 경우, SQL 파일 내의 테이블명을 변경해야 합니다.
    //
    // 변환이 필요한 SQL 문:
    //   - DROP TABLE IF EXISTS `src_table`   → DROP TABLE IF EXISTS `dst_table`
    //   - CREATE TABLE `src_table`           → CREATE TABLE `dst_table`
    //   - INSERT INTO `src_table`            → INSERT INTO `dst_table`
    //   - LOCK TABLES `src_table`            → LOCK TABLES `dst_table`
    //
    // 예시:
    //   --src-table=users --dst-table=users_backup 인 경우
    //   "INSERT INTO `users`" → "INSERT INTO `users_backup`" 으로 변환
    //
    // 주의: sed를 사용하여 스트리밍 처리 (대용량 파일도 메모리 문제 없음)
    //
    $log->info("=== Step 2: 파일 준비 ===");

    $dstBackupFile = $tempDir . "/{$dstDb}.{$dstTable}.sql";

    // 테이블명이 다를 경우에만 변환 필요
    if ($srcTable !== $dstTable) {
        // sed를 사용하여 스트리밍으로 테이블명 변환
        // - 파일을 메모리에 전부 로드하지 않고 라인 단위로 처리
        // - macOS와 Linux 호환을 위해 sed -i '' 대신 파이프(>) 사용
        $sedCmd = "sed";
        $sedCmd .= " -e " . escapeshellarg("s/DROP TABLE IF EXISTS \`{$srcTable}\`/DROP TABLE IF EXISTS \`{$dstTable}\`/g");
        $sedCmd .= " -e " . escapeshellarg("s/CREATE TABLE \`{$srcTable}\`/CREATE TABLE \`{$dstTable}\`/g");
        $sedCmd .= " -e " . escapeshellarg("s/INSERT INTO \`{$srcTable}\`/INSERT INTO \`{$dstTable}\`/g");
        $sedCmd .= " -e " . escapeshellarg("s/LOCK TABLES \`{$srcTable}\`/LOCK TABLES \`{$dstTable}\`/g");
        $sedCmd .= " " . escapeshellarg($srcBackupFile);
        $sedCmd .= " > " . escapeshellarg($dstBackupFile);

        if ($verbose) {
            $log->info("sed 명령: $sedCmd");
        }

        exec($sedCmd, $output, $returnCode);

        if ($returnCode !== 0) {
            $log->error("테이블명 변환 실패");
            exit(1);
        }

        $log->success("테이블명 변환 완료: {$srcTable} → {$dstTable}");
    } else {
        // 테이블명이 같으면 그냥 원본 파일 사용 (복사 불필요)
        $dstBackupFile = $srcBackupFile;
        $log->info("테이블명 동일 - 변환 불필요");
    }

    // 복원용 파일명 결정 (Restore 스크립트에서 사용)
    $restoreFileName = basename($dstBackupFile);

    // ============================================
    // Step 3: 대상 서버로 복원
    // ============================================
    $log->info("=== Step 3: 대상 서버로 복원 ===");

    $restoreCmd = "php " . escapeshellarg($restoreScript);
    $restoreCmd .= " " . escapeshellarg($restoreFileName);
    $restoreCmd .= " --mysql=" . escapeshellarg($dstMysql);
    $restoreCmd .= " --input=" . escapeshellarg($tempDir);
    $restoreCmd .= " --db=" . escapeshellarg($dstDb);
    $restoreCmd .= " --force";  // 이미 확인했으므로 force
    if ($verbose) {
        $restoreCmd .= " --verbose";
    }
    $restoreCmd .= " 2>&1";

    // 실행 명령어 로그
    $log->info("실행: ./ptyMysqlRestore {$restoreFileName} --mysql={$dstMysql} --db={$dstDb} --force");

    $output = [];
    exec($restoreCmd, $output, $returnCode);

    if ($verbose) {
        foreach ($output as $line) {
            echo "  $line\n";
        }
    }

    if ($returnCode !== 0) {
        $log->error("복원 실패 (exit code: $returnCode)");
        foreach ($output as $line) {
            echo "  $line\n";
        }
        exit(1);
    }

    $log->success("복원 완료");

    // ============================================
    // 완료
    // ============================================
    echo "\n";
    echo "{$GREEN}╔══════════════════════════════════════════════════════════════════╗{$RESET}\n";
    echo "{$GREEN}║                      Overwrite 완료!                             ║{$RESET}\n";
    echo "{$GREEN}╚══════════════════════════════════════════════════════════════════╝{$RESET}\n";
    echo "\n";
    echo "  {$srcMysql}:{$srcDb}.{$srcTable}\n";
    echo "    ↓\n";
    echo "  {$dstMysql}:{$dstDb}.{$dstTable}\n";
    echo "\n";

    // 정리
    cleanup($tempDir);
    $log->success("임시 파일 정리 완료");

} catch (\Exception $e) {
    $log->error($e->getMessage());
    cleanup($tempDir);
    exit(1);
}

// 바이트를 읽기 쉬운 형식으로 변환
function formatBytes($bytes) {
    if ($bytes >= 1073741824) {
        return number_format($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return number_format($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return number_format($bytes / 1024, 2) . ' KB';
    } else {
        return $bytes . ' bytes';
    }
}
