#!/usr/bin/env php
<?php
/**
 * ptyElasticGetIndexInfo
 *
 * 특정 Elasticsearch 인덱스의 상세 정보와 TOP 10 문서를 조회하는 도구
 * 설정 파일: ~/.ptyElasticConfig.ini
 *
 * Usage: ./ptyElasticGetIndexInfo <index_name>
 */

// 커맨드 라인 인자 확인
if ($argc < 2) {
    echo "Usage: $argv[0] <index_name> [search_term1] [search_term2] ...\n";
    echo "Example: $argv[0] my_index\n";
    echo "Example: $argv[0] my_index \"제3장*\"\n";
    echo "Example: $argv[0] my_index \"전기통신\" \"제11조\"\n";
    echo "Example: $argv[0] my_index \"keyword AND another\"\n";
    echo "\nNote: Multiple search terms are combined with AND operator\n";
    exit(1);
}

$indexName = $argv[1];

// 2번째 인자부터 끝까지 모든 검색어를 AND로 연결
$searchTerms = array_slice($argv, 2);
if (!empty($searchTerms)) {
    // 각 검색어를 괄호로 감싸고 AND로 연결
    $searchQuery = '(' . implode(') AND (', $searchTerms) . ')';
} else {
    $searchQuery = null;
}

// 설정 파일 경로
$configFile = getenv('HOME') . '/.ptyElasticConfig.ini';

// 설정 파일 확인
if (!file_exists($configFile)) {
    echo "Error: 설정 파일을 찾을 수 없습니다: $configFile\n";
    echo "\n설정 파일 예시:\n";
    echo "[elastic]\n";
    echo "host=https://localhost:9200\n";
    echo "user=elastic\n";
    echo "password=yourpassword\n";
    exit(1);
}

// 설정 파일 읽기
$config = parse_ini_file($configFile, true);

if (!isset($config['elastic'])) {
    echo "Error: 설정 파일에 [elastic] 섹션이 없습니다.\n";
    exit(1);
}

$elasticConfig = $config['elastic'];
$host = $elasticConfig['host'] ?? '';
$user = $elasticConfig['user'] ?? '';
$password = $elasticConfig['password'] ?? '';

if (empty($host)) {
    echo "Error: host 설정이 필요합니다.\n";
    exit(1);
}

// Elasticsearch API 호출
function callElasticAPI($url, $user, $password, $method = 'GET', $body = null) {
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

    if ($body !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    }

    if (!empty($user) && !empty($password)) {
        curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
    }

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if (curl_errno($ch)) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new Exception("cURL Error: $error");
    }

    curl_close($ch);

    if ($httpCode !== 200) {
        throw new Exception("HTTP Error: $httpCode - $response");
    }

    return $response;
}

// JSON을 보기 좋게 출력
function printJson($data, $indent = 0) {
    $prefix = str_repeat("  ", $indent);

    if (is_array($data)) {
        foreach ($data as $key => $value) {
            if (is_array($value) || is_object($value)) {
                echo $prefix . "$key:\n";
                printJson($value, $indent + 1);
            } else {
                echo $prefix . "$key: $value\n";
            }
        }
    } elseif (is_object($data)) {
        foreach ($data as $key => $value) {
            if (is_array($value) || is_object($value)) {
                echo $prefix . "$key:\n";
                printJson($value, $indent + 1);
            } else {
                echo $prefix . "$key: $value\n";
            }
        }
    }
}

// 바이트를 읽기 쉬운 형식으로 변환
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 {
    echo "Elasticsearch 인덱스 정보 조회\n";
    echo "Host: $host\n";
    echo "Index: $indexName\n";
    echo str_repeat("=", 100) . "\n\n";

    // 1. 인덱스 기본 정보 조회
    echo "[ 1. 기본 정보 ]\n";
    echo str_repeat("-", 100) . "\n";

    $catUrl = rtrim($host, '/') . '/_cat/indices/' . urlencode($indexName) . '?v&format=json&bytes=b';
    $catResponse = callElasticAPI($catUrl, $user, $password);
    $catData = json_decode($catResponse, true);

    if (empty($catData)) {
        throw new Exception("인덱스를 찾을 수 없습니다: $indexName");
    }

    $indexInfo = $catData[0];
    printf("상태(Health): %s\n", $indexInfo['health'] ?? 'N/A');
    printf("상태(Status): %s\n", $indexInfo['status'] ?? 'N/A');
    printf("Primary 샤드: %s\n", $indexInfo['pri'] ?? 'N/A');
    printf("Replica 샤드: %s\n", $indexInfo['rep'] ?? 'N/A');
    printf("문서 수: %s\n", number_format($indexInfo['docs.count'] ?? 0));
    printf("삭제된 문서 수: %s\n", number_format($indexInfo['docs.deleted'] ?? 0));
    printf("저장 용량: %s\n", formatBytes($indexInfo['store.size'] ?? 0));
    printf("Primary 용량: %s\n", formatBytes($indexInfo['pri.store.size'] ?? 0));
    echo "\n";

    // 2. 인덱스 설정 정보
    echo "[ 2. 인덱스 설정 ]\n";
    echo str_repeat("-", 100) . "\n";

    $settingsUrl = rtrim($host, '/') . '/' . urlencode($indexName) . '/_settings';
    $settingsResponse = callElasticAPI($settingsUrl, $user, $password);
    $settingsData = json_decode($settingsResponse, true);

    if (isset($settingsData[$indexName]['settings']['index'])) {
        $settings = $settingsData[$indexName]['settings']['index'];
        printf("생성 날짜: %s\n", $settings['creation_date'] ?? 'N/A');
        if (isset($settings['creation_date'])) {
            $timestamp = (int)(floatval($settings['creation_date']) / 1000);
            printf("생성 날짜(변환): %s\n", date('Y-m-d H:i:s', $timestamp));
        }
        printf("UUID: %s\n", $settings['uuid'] ?? 'N/A');
        printf("버전: %s\n", $settings['version']['created'] ?? 'N/A');
        printf("샤드 수: %s\n", $settings['number_of_shards'] ?? 'N/A');
        printf("Replica 수: %s\n", $settings['number_of_replicas'] ?? 'N/A');
    }
    echo "\n";

    // 3. 인덱스 통계
    echo "[ 3. 인덱스 통계 ]\n";
    echo str_repeat("-", 100) . "\n";

    $statsUrl = rtrim($host, '/') . '/' . urlencode($indexName) . '/_stats';
    $statsResponse = callElasticAPI($statsUrl, $user, $password);
    $statsData = json_decode($statsResponse, true);

    if (isset($statsData['indices'][$indexName]['total'])) {
        $total = $statsData['indices'][$indexName]['total'];

        if (isset($total['docs'])) {
            printf("총 문서 수: %s\n", number_format($total['docs']['count'] ?? 0));
            printf("삭제된 문서: %s\n", number_format($total['docs']['deleted'] ?? 0));
        }

        if (isset($total['store'])) {
            printf("총 저장 용량: %s\n", formatBytes($total['store']['size_in_bytes'] ?? 0));
        }

        if (isset($total['indexing'])) {
            printf("색인 작업 수: %s\n", number_format($total['indexing']['index_total'] ?? 0));
            printf("색인 소요 시간: %s ms\n", number_format($total['indexing']['index_time_in_millis'] ?? 0));
        }

        if (isset($total['search'])) {
            printf("검색 작업 수: %s\n", number_format($total['search']['query_total'] ?? 0));
            printf("검색 소요 시간: %s ms\n", number_format($total['search']['query_time_in_millis'] ?? 0));
        }
    }
    echo "\n";

    // 4. 매핑 정보 (필드 목록)
    echo "[ 4. 필드 매핑 ]\n";
    echo str_repeat("-", 100) . "\n";

    $mappingUrl = rtrim($host, '/') . '/' . urlencode($indexName) . '/_mapping';
    $mappingResponse = callElasticAPI($mappingUrl, $user, $password);
    $mappingData = json_decode($mappingResponse, true);

    if (isset($mappingData[$indexName]['mappings']['properties'])) {
        $properties = $mappingData[$indexName]['mappings']['properties'];
        printf("%-40s %-15s\n", "필드명", "타입");
        echo str_repeat("-", 60) . "\n";

        foreach ($properties as $fieldName => $fieldInfo) {
            $type = $fieldInfo['type'] ?? 'object';
            printf("%-40s %-15s\n", substr($fieldName, 0, 40), $type);
        }

        $totalFields = count($properties);
        printf("\n총 필드 수: %d\n", $totalFields);
    }
    echo "\n";

    // 5. TOP 50 문서 조회
    if ($searchQuery) {
        echo "[ 5. 검색 결과 TOP 50 (검색어: \"$searchQuery\") ]\n";
    } else {
        echo "[ 5. 샘플 문서 TOP 50 ]\n";
    }
    echo str_repeat("-", 100) . "\n";

    $searchUrl = rtrim($host, '/') . '/' . urlencode($indexName) . '/_search';

    // 검색 쿼리 생성
    if ($searchQuery) {
        // 검색어가 있으면 query_string 사용 (와일드카드 지원)
        $query = [
            'query_string' => [
                'query' => $searchQuery,
                'default_operator' => 'AND'
            ]
        ];
    } else {
        // 검색어가 없으면 match_all
        $query = ['match_all' => (object)[]];
    }

    $searchBody = json_encode([
        'size' => 50,
        'query' => $query
    ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

    // 쿼리 표시
    $cyanColor = "\033[1;36m";  // 밝은 청록색
    $resetColor = "\033[0m";
    echo "\n{$cyanColor}[사용된 Elasticsearch 쿼리]{$resetColor}\n";
    echo str_repeat("-", 100) . "\n";
    echo $searchBody . "\n";
    echo str_repeat("-", 100) . "\n\n";

    $searchResponse = callElasticAPI($searchUrl, $user, $password, 'POST', $searchBody);
    $searchData = json_decode($searchResponse, true);

    if (isset($searchData['hits']['hits']) && count($searchData['hits']['hits']) > 0) {
        $hits = $searchData['hits']['hits'];

        // 색상 코드 정의
        $yellowColor = "\033[1;33m";  // 밝은 노란색
        $greenColor = "\033[1;32m";   // 밝은 녹색
        $resetColor = "\033[0m";       // 색상 리셋

        foreach ($hits as $idx => $hit) {
            $docId = $hit['_id'];
            $docUrl = rtrim($host, '/') . '/' . urlencode($indexName) . '/_doc/' . urlencode($docId);

            echo "\n문서 #" . ($idx + 1) . " (ID: {$greenColor}{$docId}{$resetColor}, URL: {$greenColor}{$docUrl}{$resetColor})\n";
            echo str_repeat("-", 120) . "\n";

            // 메타데이터 필드 먼저 표시
            $metadataFields = ['_index', '_id', '_version', '_seq_no', '_primary_term', '_score'];
            foreach ($metadataFields as $metaField) {
                if (isset($hit[$metaField])) {
                    $value = $hit[$metaField];
                    echo "  {$yellowColor}{$metaField}{$resetColor}: $value\n";
                }
            }

            // 구분선
            if (!empty($hit['_source'])) {
                echo "  " . str_repeat("-", 80) . "\n";
            }

            // _source 필드 표시
            $source = $hit['_source'];

            foreach ($source as $key => $value) {
                $fullFieldName = "_source.$key";
                if (is_array($value) || is_object($value)) {
                    echo "  {$yellowColor}{$fullFieldName}{$resetColor}: " . json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
                } else {
                    $valueStr = is_string($value) ? $value : json_encode($value);
                    echo "  {$yellowColor}{$fullFieldName}{$resetColor}: $valueStr\n";
                }
            }
        }

        echo "\n총 조회된 문서 수: " . count($hits) . "\n";
        echo "인덱스 전체 문서 수: " . number_format($searchData['hits']['total']['value'] ?? 0) . "\n";
    } else {
        echo "문서가 없습니다.\n";
    }

    echo "\n" . str_repeat("=", 100) . "\n";
    echo "조회 완료\n";

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