#!/usr/bin/env php
<?php
/**
 * ptyAIGetVector
 *
 * AI API를 통해 텍스트의 벡터 임베딩을 얻는 CLI 도구
 *
 * 설정 파일: ~/.ptyAIConfig.ini
 *
 * Usage: ./ptyAIGetVector "텍스트" [--ai=섹션명] [--model=모델명]
 *
 * 지원 provider:
 * - openai: text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002
 * - google: text-embedding-004
 * - ollama: nomic-embed-text, mxbai-embed-large, all-minilm
 *
 * 참고: anthropic(Claude)는 임베딩 API를 제공하지 않습니다.
 */

namespace platyFramework;

require_once __DIR__ . '/ptyLibrary_PHP/cli/ptyCliOptionParser.php';
require_once __DIR__ . '/ptyLibrary_PHP/ai/ptyAIConfig.php';

// 인자 파싱
$parsed = ptyCliOptionParser::parse($argv);
$positionalArgs = $parsed['positional'];
$options = $parsed['options'];
$aiSection = isset($options['ai']) ? $options['ai'] : 'default';
$modelOverride = isset($options['model']) ? $options['model'] : null;
$verbose = isset($options['verbose']);
$jsonOutput = isset($options['json']);
$dimensions = isset($options['dimensions']) ? intval($options['dimensions']) : null;

// --edit 옵션: vi로 설정 파일 열기
if (isset($options['edit'])) {
    $editor = getenv('EDITOR') ? getenv('EDITOR') : 'vi';
    $configPath = ptyAIConfig::getConfigPath();
    passthru("$editor " . escapeshellarg($configPath));
    exit(0);
}

// 도움말
if (isset($options['help'])) {
    printHelp($argv[0]);
    exit(0);
}

// 텍스트 입력: 인자 또는 stdin
if (empty($positionalArgs)) {
    // stdin에서 읽기
    if (posix_isatty(STDIN)) {
        fwrite(STDERR, "텍스트를 입력하세요 (Ctrl+D로 완료):\n");
    }
    $text = file_get_contents('php://stdin');
    $text = trim($text);
    if (empty($text)) {
        fwrite(STDERR, "Error: 텍스트가 필요합니다.\n");
        fwrite(STDERR, "도움말: {$argv[0]} --help\n");
        exit(1);
    }
} else {
    $text = $positionalArgs[0];
}

try {
    // AI 설정 로드
    $config = ptyAIConfig::load($aiSection);
    $provider = $config['provider'];

    // anthropic은 임베딩 API 미지원
    if ($provider === 'anthropic') {
        fwrite(STDERR, "Error: anthropic(Claude)는 임베딩 API를 지원하지 않습니다.\n");
        fwrite(STDERR, "openai, google, ollama 섹션을 사용하세요.\n");
        exit(1);
    }

    // 클라이언트 생성
    $client = ptyAIConfig::createClient($aiSection);

    // 디버그 모드 설정
    if ($verbose && method_exists($client, 'setDebug')) {
        $client->setDebug(true);
    }

    // 임베딩 모델 결정
    $model = $modelOverride ? $modelOverride : ptyAIConfig::getDefaultEmbeddingModel($provider);

    if ($verbose) {
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
        fwrite(STDERR, "Provider: {$provider}\n");
        fwrite(STDERR, "Model: {$model}\n");
        fwrite(STDERR, "Section: {$aiSection}\n");
        if ($dimensions) {
            fwrite(STDERR, "Dimensions: {$dimensions}\n");
        }
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
        fwrite(STDERR, "Text: " . mb_substr($text, 0, 100) . (mb_strlen($text) > 100 ? '...' : '') . "\n");
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
        fwrite(STDERR, "API 호출 중...\n");
    }

    $startTime = microtime(true);

    // 임베딩 API 호출 (클래스 메서드 사용)
    if ($provider === 'openai') {
        $result = $client->getEmbedding($text, $model, $dimensions);
    } else {
        $result = $client->getEmbedding($text, $model);
    }

    $elapsed = round((microtime(true) - $startTime) * 1000);

    if ($result === false) {
        fwrite(STDERR, "Error: 임베딩 API 호출에 실패했습니다.\n");
        exit(1);
    }

    $embedding = $result['embedding'];
    $response = $result['response'];
    $usage = isset($result['usage']) ? $result['usage'] : null;

    if ($verbose) {
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
        fwrite(STDERR, "응답 시간: {$elapsed}ms\n");
        fwrite(STDERR, "벡터 차원: " . count($embedding) . "\n");
        if ($usage) {
            fwrite(STDERR, "토큰 사용량: {$usage} tokens\n");
        }
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
    }

    // 출력
    if ($jsonOutput) {
        $output = array(
            'request' => array(
                'provider' => $provider,
                'model' => $model,
                'text' => $text,
            ),
            'response' => array(
                'embedding' => $embedding,
                'dimensions' => count($embedding),
                'elapsed_ms' => $elapsed,
            ),
        );
        if ($dimensions) {
            $output['request']['dimensions'] = $dimensions;
        }
        if ($usage) {
            $output['response']['tokens'] = $usage;
        }
        echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
    } else {
        // 벡터만 출력 (JSON 배열)
        echo json_encode($response) . "\n";
    }

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

/**
 * 도움말 출력
 */
function printHelp($scriptName)
{
    fwrite(STDERR, "사용법: {$scriptName} [\"텍스트\"] [옵션]\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "텍스트를 벡터 임베딩으로 변환합니다.\n");
    fwrite(STDERR, "텍스트 인자가 없으면 stdin에서 읽습니다 (Ctrl+D로 완료).\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "옵션:\n");
    fwrite(STDERR, "  --ai=섹션명              INI 파일 섹션 (기본값: default)\n");
    fwrite(STDERR, "  --model=모델명            임베딩 모델 오버라이드\n");
    fwrite(STDERR, "  --dimensions=N           출력 벡터 차원 수 (OpenAI text-embedding-3-* 전용)\n");
    fwrite(STDERR, "  --verbose                상세 정보 출력\n");
    fwrite(STDERR, "  --json                   요청/응답 전체를 JSON으로 출력\n");
    fwrite(STDERR, "  --edit                   설정 파일을 에디터로 열기\n");
    fwrite(STDERR, "  --help                   도움말 출력\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "지원 프로바이더 및 모델:\n");
    fwrite(STDERR, "  openai:\n");
    fwrite(STDERR, "    - text-embedding-3-small (기본값, 1536차원, 저렴)\n");
    fwrite(STDERR, "    - text-embedding-3-large (3072차원, 고성능)\n");
    fwrite(STDERR, "    - text-embedding-ada-002 (1536차원, 레거시)\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "  google:\n");
    fwrite(STDERR, "    - text-embedding-004 (기본값, 768차원)\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "  ollama:\n");
    fwrite(STDERR, "    - nomic-embed-text (기본값, 768차원)\n");
    fwrite(STDERR, "    - mxbai-embed-large (1024차원)\n");
    fwrite(STDERR, "    - all-minilm (384차원, 경량)\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "  voyageai:\n");
    fwrite(STDERR, "    - voyage-3-large (기본값, 1024차원, 고성능)\n");
    fwrite(STDERR, "    - voyage-3 (1024차원)\n");
    fwrite(STDERR, "    - voyage-3-lite (512차원, 경량)\n");
    fwrite(STDERR, "    - voyage-code-3 (1024차원, 코드 특화)\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "주의: anthropic(Claude)는 임베딩 API를 지원하지 않습니다.\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "예시:\n");
    fwrite(STDERR, "  {$scriptName} \"안녕하세요\"                        # 기본 설정으로 임베딩\n");
    fwrite(STDERR, "  {$scriptName} \"Hello\" --ai=openai                 # OpenAI 사용\n");
    fwrite(STDERR, "  {$scriptName} \"Hello\" --ai=openai --model=text-embedding-3-large\n");
    fwrite(STDERR, "  {$scriptName} \"Hello\" --ai=openai --dimensions=512   # 차원 축소\n");
    fwrite(STDERR, "  {$scriptName} \"테스트\" --ai=ollama --verbose       # Ollama + 상세 로그\n");
    fwrite(STDERR, "  {$scriptName} \"테스트\" --ai=voyageai               # VoyageAI 사용\n");
    fwrite(STDERR, "  {$scriptName} \"테스트\" --json                      # 전체 JSON 출력\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "입력 방법:\n");
    fwrite(STDERR, "  {$scriptName} --ai=voyageai                        # stdin에서 입력 (Ctrl+D로 완료)\n");
    fwrite(STDERR, "  {$scriptName} --ai=voyageai < file.txt             # 파일에서 입력 (리다이렉션)\n");
    fwrite(STDERR, "  cat file.txt | {$scriptName} --ai=voyageai         # 파일에서 입력 (파이프)\n");
    fwrite(STDERR, "  {$scriptName} \"\$(pbpaste)\" --ai=voyageai          # 클립보드에서 입력 (macOS)\n");
    fwrite(STDERR, "  {$scriptName} \"\$(xclip -o)\" --ai=voyageai         # 클립보드에서 입력 (Linux)\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "설정 파일: ~/.ptyAIConfig.ini\n");
    fwrite(STDERR, ptyAIConfig::getConfigExample() . "\n");
}
