#!/usr/bin/env php
<?php
/**
 * ptyElasticGetIndex
 *
 * 특정 Elasticsearch 인덱스의 상세 정보와 문서를 조회하는 도구
 * 설정 파일: ~/.ptyElasticConfig.ini
 *
 * Usage: ./ptyElasticGetIndex <index_name> [search_term] [--elastic=섹션명]
 */

namespace platyFramework;

require_once __DIR__ . '/ptyLibrary_PHP/cli/ptyCliOptionParser.php';
require_once __DIR__ . '/ptyLibrary_PHP/elastic/ptyElasticConfig.php';

// 인자 파싱
$parsed = ptyCliOptionParser::parse($argv);
$positionalArgs = $parsed['positional'];
$options = $parsed['options'];
$elasticSection = $options['elastic'] ?? 'default';
$limit = isset($options['limit']) ? (int)$options['limit'] : 50;
$verbose = isset($options['verbose']);

// 예약된 옵션 (필드 검색에서 제외)
$reservedOptions = ['elastic', 'limit', 'verbose', 'help'];

// 필드 검색 옵션 추출 (--필드명=검색어)
$fieldSearches = [];
foreach ($options as $key => $value) {
    if (!in_array($key, $reservedOptions) && $value !== true) {
        $fieldSearches[$key] = $value;
    }
}

// 도움말 또는 인덱스명 확인
if (empty($positionalArgs) || isset($options['help'])) {
    echo "사용법: {$argv[0]} <index_name> [search_term1] [search_term2] ... [옵션]\n";
    echo "\n";
    echo "옵션:\n";
    echo "  --limit=N           결과 문서 수 (기본값: 50)\n";
    echo "  --elastic=섹션명    INI 파일 섹션 (기본값: default)\n";
    echo "  --verbose           상세 로그 출력\n";
    echo "  --help              도움말 출력\n";
    echo "\n";
    echo "필드 검색:\n";
    echo "  --필드명=검색어      특정 필드에서 검색 (wildcard 지원)\n";
    echo "    *검색어            검색어로 끝나는 값\n";
    echo "    검색어*            검색어로 시작하는 값\n";
    echo "    *검색어*           검색어가 포함된 값\n";
    echo "\n";
    echo "예시:\n";
    echo "  {$argv[0]} my_index\n";
    echo "  {$argv[0]} my_index --limit=5\n";
    echo "  {$argv[0]} my_index \"제3장*\"\n";
    echo "  {$argv[0]} my_index \"전기통신\" \"제11조\"\n";
    echo "  {$argv[0]} my_index \"keyword AND another\"\n";
    echo "  {$argv[0]} my_index --elastic=production --limit=10\n";
    echo "  {$argv[0]} my_index --law_name=\"*민법*\"\n";
    echo "  {$argv[0]} my_index --law_name=\"민법*\" --lw_category=\"법률\"\n";
    echo "\n";
    echo "Note: Multiple search terms and field searches are combined with AND operator\n";
    echo "\n";
    echo "설정 파일: ~/.ptyElasticConfig.ini\n";
    echo ptyElasticConfig::getConfigExample() . "\n";
    exit(isset($options['help']) ? 0 : 1);
}

$indexName = $positionalArgs[0];

// 2번째 인자부터 끝까지 검색어로 사용
$searchTerms = array_slice($positionalArgs, 1);
if (!empty($searchTerms)) {
    $searchQuery = '(' . implode(') AND (', $searchTerms) . ')';
} else {
    $searchQuery = null;
}

// 바이트를 읽기 쉬운 형식으로 변환
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 {
    // Elasticsearch 연결
    $connection = ptyElasticConfig::connect($elasticSection);
    $elastic = $connection['client'];
    $elastic->setDebug($verbose);
    $config = $connection['config'];
    $authMethod = $connection['authMethod'];

    echo "Elasticsearch 인덱스 정보 조회\n";
    echo "Host: {$config['host']} ({$authMethod})\n";
    echo "Index: $indexName\n";
    echo str_repeat("=", 100) . "\n\n";

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

    $catData = $elastic->get('_cat/indices/' . urlencode($indexName) . '?v&format=json&bytes=b');

    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";

    $settingsData = $elastic->get(urlencode($indexName) . '/_settings');

    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";

    $statsData = $elastic->get(urlencode($indexName) . '/_stats');

    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";

    $mappingData = $elastic->get(urlencode($indexName) . '/_mapping');

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

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

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

    // 5. TOP N 문서 조회
    $hasSearch = $searchQuery || !empty($fieldSearches);
    if ($hasSearch) {
        $searchDesc = [];
        if ($searchQuery) {
            $searchDesc[] = "검색어: \"$searchQuery\"";
        }
        foreach ($fieldSearches as $field => $value) {
            $searchDesc[] = "$field: \"$value\"";
        }
        echo "[ 5. 검색 결과 TOP {$limit} (" . implode(', ', $searchDesc) . ") ]\n";
    } else {
        echo "[ 5. 샘플 문서 TOP {$limit} ]\n";
    }
    echo str_repeat("-", 100) . "\n";

    // 검색 쿼리 생성
    $mustClauses = [];

    // 일반 검색어 (positional args)
    if ($searchQuery) {
        $mustClauses[] = [
            'query_string' => [
                'query' => $searchQuery,
                'default_operator' => 'AND'
            ]
        ];
    }

    // 필드 검색 (--필드명=검색어)
    foreach ($fieldSearches as $field => $value) {
        // wildcard 포함 여부 확인
        if (strpos($value, '*') !== false) {
            $mustClauses[] = [
                'wildcard' => [
                    $field => [
                        'value' => $value,
                        'case_insensitive' => true
                    ]
                ]
            ];
        } else {
            // wildcard 없으면 term 쿼리 (keyword 필드) + match 쿼리 (text 필드) 동시 사용
            $mustClauses[] = [
                'bool' => [
                    'should' => [
                        ['term' => [$field => $value]],
                        ['match' => [$field => $value]]
                    ],
                    'minimum_should_match' => 1
                ]
            ];
        }
    }

    // 최종 쿼리 생성
    if (empty($mustClauses)) {
        $query = ['match_all' => (object)[]];
    } elseif (count($mustClauses) === 1) {
        $query = $mustClauses[0];
    } else {
        $query = [
            'bool' => [
                'must' => $mustClauses
            ]
        ];
    }

    $searchBody = [
        'size' => $limit,
        'query' => $query
    ];

    // 쿼리 표시
    $cyanColor = "\033[1;36m";
    $resetColor = "\033[0m";
    echo "\n{$cyanColor}[사용된 Elasticsearch 쿼리]{$resetColor}\n";
    echo str_repeat("-", 100) . "\n";
    echo json_encode($searchBody, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
    echo str_repeat("-", 100) . "\n\n";

    $searchData = $elastic->search(urlencode($indexName) . '/_search', $searchBody);

    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($config['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);
}
