#!/usr/bin/env php
<?php
/**
 * ptyMysqlBackup
 *
 * MySQL 데이터베이스/테이블 백업 도구
 * 설정 파일: ~/.ptyMysqlConfig.ini
 *
 * Usage: ./ptyMysqlBackup <database> <table> [options]
 *        ./ptyMysqlBackup * *  (전체 백업)
 */

namespace platyFramework;

require_once __DIR__ . '/ptyLibrary_PHP/cli/ptyCliOptionParser.php';
require_once __DIR__ . '/ptyLibrary_PHP/mysql/ptyMysqlConfig.php';

// 인자 파싱
$parsed = ptyCliOptionParser::parse($argv);
$positionalArgs = $parsed['positional'];
$options = $parsed['options'];
$mysqlSection = $options['mysql'] ?? 'default';
$verbose = isset($options['verbose']);
$outputDir = $options['output'] ?? '.';

// 도움말 또는 필수 인자 확인
if (count($positionalArgs) < 2 || isset($options['help'])) {
    echo "사용법: {$argv[0]} <database> <table> [옵션]\n";
    echo "\n";
    echo "인자:\n";
    echo "  <database>          데이터베이스명 (* = 전체)\n";
    echo "  <table>             테이블명 (* = 전체)\n";
    echo "\n";
    echo "옵션:\n";
    echo "  --mysql=섹션명      INI 파일 섹션 (기본값: default)\n";
    echo "  --output=경로       출력 디렉토리 (기본값: 현재 디렉토리)\n";
    echo "  --verbose           상세 로그 출력\n";
    echo "  --help              도움말 출력\n";
    echo "\n";
    echo "예시:\n";
    echo "  {$argv[0]} mydb users                    # mydb.users.sql 생성\n";
    echo "  {$argv[0]} mydb *                        # mydb의 모든 테이블 백업\n";
    echo "  {$argv[0]} * *                           # 전체 백업\n";
    echo "  {$argv[0]} mydb users --output=/backup   # /backup/mydb.users.sql 생성\n";
    echo "  {$argv[0]} mydb users --mysql=production # production 섹션 사용\n";
    echo "\n";
    echo "기본 mysqldump 옵션:\n";
    echo "  --default-character-set=utf8mb4\n";
    echo "  --routines --events\n";
    echo "  --add-drop-table --add-drop-database\n";
    echo "  --complete-insert --extended-insert=TRUE\n";
    echo "  --single-transaction --ssl-mode=DISABLED\n";
    echo "  --max-allowed-packet=1G\n";
    echo "\n";
    echo "설정 파일: ~/.ptyMysqlConfig.ini\n";
    echo ptyMysqlConfig::getConfigExample() . "\n";
    exit(isset($options['help']) ? 0 : 1);
}

$dbPattern = $positionalArgs[0];
$tablePattern = $positionalArgs[1];

// 원본 명령어 저장 (백업 파일 주석용)
$originalCommand = implode(' ', $argv);

// 타임스탬프 로그 함수
function logMessage($message, $verbose = false, $isVerbose = false) {
    if ($isVerbose && !$verbose) {
        return;
    }
    $timestamp = date('Y-m-d H:i:s');
    echo "[$timestamp] $message\n";
}

// mysqldump 명령 생성
function getMysqldumpCmd($host, $user, $password, $dbName, $tableName = null) {
    $cmd = "mysqldump";
    $cmd .= " -h " . escapeshellarg($host);
    $cmd .= " -u " . escapeshellarg($user);
    $cmd .= " -p" . escapeshellarg($password);
    $cmd .= " --default-character-set=utf8mb4";
    $cmd .= " --routines --events";
    $cmd .= " --add-drop-table --add-drop-database";
    $cmd .= " --complete-insert --extended-insert=TRUE";
    $cmd .= " --single-transaction";
    $cmd .= " --ssl-mode=DISABLED";
    $cmd .= " --max-allowed-packet=1G";
    $cmd .= " " . escapeshellarg($dbName);

    if ($tableName) {
        $cmd .= " " . escapeshellarg($tableName);
    }

    return $cmd;
}

// 백업 실행 함수
function backupTable($host, $user, $password, $dbName, $tableName, $outputDir, $verbose, $originalCommand) {
    $outputFile = rtrim($outputDir, '/') . "/{$dbName}.{$tableName}.sql";
    $errorFile = sys_get_temp_dir() . "/mysqldump_err_" . getmypid() . ".txt";

    // 백업 정보 주석 생성
    $backupTime = date('Y-m-d H:i:s');
    $header = "-- ============================================\n";
    $header .= "-- 백업 시간: $backupTime\n";
    $header .= "-- 실행 명령: $originalCommand\n";
    $header .= "-- 데이터베이스: $dbName\n";
    $header .= "-- 테이블: $tableName\n";
    $header .= "-- ============================================\n\n";

    // 주석을 먼저 파일에 작성
    file_put_contents($outputFile, $header);

    $cmd = getMysqldumpCmd($host, $user, $password, $dbName, $tableName);
    // stdout은 SQL 파일에 append, stderr는 임시 파일로 분리
    $cmd .= " >> " . escapeshellarg($outputFile) . " 2>" . escapeshellarg($errorFile);

    if ($verbose) {
        logMessage("명령: $cmd", $verbose, true);
    }

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

    // 에러 확인
    $errorOutput = file_exists($errorFile) ? trim(file_get_contents($errorFile)) : '';
    @unlink($errorFile);

    if ($returnCode !== 0) {
        logMessage("ERROR: {$dbName}.{$tableName} 백업 실패", true);
        if ($errorOutput) {
            logMessage($errorOutput, true);
        }
        return false;
    }

    // 파일 크기 확인
    if (file_exists($outputFile)) {
        $size = filesize($outputFile);
        $sizeStr = formatBytes($size);
        logMessage("OK: {$dbName}.{$tableName}.sql ($sizeStr)", true);
    }

    return true;
}

// 바이트를 읽기 쉬운 형식으로 변환
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';
    }
}

try {
    // MySQL 연결
    $conn = ptyMysqlConfig::connect($mysqlSection);
    $connection = $conn['connection'];
    $config = $conn['config'];

    logMessage("MySQL 백업 시작", true);
    logMessage("Host: {$config['host']}", true);
    logMessage("User: {$config['username']}", true);
    logMessage("Output: $outputDir", true);
    echo str_repeat("=", 60) . "\n";

    // 출력 디렉토리 생성
    if (!is_dir($outputDir)) {
        if (!mkdir($outputDir, 0755, true)) {
            throw new \Exception("출력 디렉토리 생성 실패: $outputDir");
        }
    }

    // 시스템 DB 제외 목록
    $systemDbs = ['information_schema', 'performance_schema', 'mysql', 'sys'];

    $totalBackups = 0;
    $successBackups = 0;

    // 데이터베이스 목록 조회
    if ($dbPattern === '*') {
        $dbResult = mysqli_query($connection, "SHOW DATABASES");
        $databases = [];
        while ($row = mysqli_fetch_row($dbResult)) {
            if (!in_array($row[0], $systemDbs)) {
                $databases[] = $row[0];
            }
        }
    } else {
        $databases = [$dbPattern];
    }

    foreach ($databases as $dbName) {
        // x_ 접두사 DB 제외
        if (strpos($dbName, 'x_') === 0) {
            logMessage("SKIP: $dbName (x_ prefix)", true);
            continue;
        }

        logMessage("", true);
        logMessage("Database: $dbName", true);
        echo str_repeat("-", 40) . "\n";

        // 테이블 목록 조회
        if ($tablePattern === '*') {
            $tableResult = mysqli_query($connection, "SHOW TABLES FROM `$dbName`");
            if (!$tableResult) {
                logMessage("ERROR: $dbName 테이블 조회 실패", true);
                continue;
            }

            $tables = [];
            while ($row = mysqli_fetch_row($tableResult)) {
                $tables[] = $row[0];
            }
        } else {
            $tables = [$tablePattern];
        }

        foreach ($tables as $tableName) {
            $totalBackups++;
            if (backupTable($config['host'], $config['username'], $config['password'], $dbName, $tableName, $outputDir, $verbose, $originalCommand)) {
                $successBackups++;
            }
        }
    }

    mysqli_close($connection);

    echo "\n" . str_repeat("=", 60) . "\n";
    logMessage("백업 완료: $successBackups / $totalBackups", true);

    if ($successBackups < $totalBackups) {
        exit(1);
    }

} catch (\Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
    exit(1);
}
