#!/usr/bin/env php
<?php
/**
 * ptyAIStatistics
 *
 * AI API 섹션별 사용량 및 통계 정보 조회 CLI 도구
 *
 * 설정 파일: ~/.ptyAIConfig.ini
 *
 * Usage: ./ptyAIStatistics [--ai=섹션명] [--verbose] [--json]
 *
 * 지원 provider:
 * - anthropic: Claude API (Admin API 필요)
 * - openai: ChatGPT API (Usage/Costs API)
 * - google: Gemini API (모델 목록)
 * - ollama: Ollama (로컬 모델 목록)
 */

namespace platyFramework;

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

// 인자 파싱
$parsed = ptyCliOptionParser::parse($argv);
$options = $parsed['options'];
$aiSection = $options['ai'] ?? null;  // null이면 모든 섹션
$verbose = isset($options['verbose']);
$jsonOutput = isset($options['json']);
$days = isset($options['days']) ? (int)$options['days'] : 30;
$showDaily = isset($options['daily']);

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

// 도움말
if (isset($options['help'])) {
    fwrite(STDERR, "사용법: {$argv[0]} [옵션]\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "옵션:\n");
    fwrite(STDERR, "  --ai=섹션명              특정 섹션만 조회 (미지정시 전체)\n");
    fwrite(STDERR, "  --days=일수              조회 기간 (기본값: 30일)\n");
    fwrite(STDERR, "  --daily                  날짜별 상세 출력\n");
    fwrite(STDERR, "  --verbose                상세 정보 출력 (API 요청/응답)\n");
    fwrite(STDERR, "  --json                   JSON 형식으로 출력\n");
    fwrite(STDERR, "  --edit                   설정 파일을 vi로 열기\n");
    fwrite(STDERR, "  --help                   도움말 출력\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "Provider별 조회 정보:\n");
    fwrite(STDERR, "  anthropic: 사용량 통계 (adminApiKey=sk-ant-admin... 필요)\n");
    fwrite(STDERR, "  openai:    사용량 및 비용 통계 (adminApiKey=sk-admin... 필요)\n");
    fwrite(STDERR, "  google:    모델 목록 및 Rate Limit 정보\n");
    fwrite(STDERR, "  ollama:    로컬 모델 목록 및 실행 중인 모델\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "INI 설정 예시 (adminApiKey 사용):\n");
    fwrite(STDERR, "  [claude-admin]\n");
    fwrite(STDERR, "  provider=anthropic\n");
    fwrite(STDERR, "  apiKey=sk-ant-api03-xxx\n");
    fwrite(STDERR, "  adminApiKey=sk-ant-admin01-xxx\n");
    fwrite(STDERR, "\n");
    fwrite(STDERR, "  [openai-admin]\n");
    fwrite(STDERR, "  provider=openai\n");
    fwrite(STDERR, "  apiKey=sk-proj-xxx\n");
    fwrite(STDERR, "  adminApiKey=sk-admin-xxx\n");
    fwrite(STDERR, "\n");

    // 현재 설정 파일 내용 표시
    $configPath = ptyAIConfig::getConfigPath();
    if (file_exists($configPath)) {
        fwrite(STDERR, "설정 파일: {$configPath}\n");
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
        $sections = parse_ini_file($configPath, true);
        if ($sections) {
            foreach ($sections as $name => $config) {
                $provider = $config['provider'] ?? '(없음)';
                $model = $config['model'] ?? ptyAIConfig::getDefaultModel($provider);
                $apiKey = isset($config['apiKey']) ? substr($config['apiKey'], 0, 12) . '...' : '(없음)';
                fwrite(STDERR, "[{$name}] provider={$provider}, model={$model}, apiKey={$apiKey}\n");
            }
        }
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
    } else {
        fwrite(STDERR, "설정 파일 없음: {$configPath}\n");
    }
    exit(0);
}

// 설정 파일 확인
$configPath = ptyAIConfig::getConfigPath();
if (!file_exists($configPath)) {
    fwrite(STDERR, "Error: 설정 파일을 찾을 수 없습니다: {$configPath}\n");
    fwrite(STDERR, ptyAIConfig::getConfigExample() . "\n");
    exit(1);
}

$allSections = parse_ini_file($configPath, true);
if (!$allSections) {
    fwrite(STDERR, "Error: 설정 파일을 파싱할 수 없습니다.\n");
    exit(1);
}

// 조회할 섹션 결정
$sectionsToCheck = [];
if ($aiSection) {
    if (!isset($allSections[$aiSection])) {
        fwrite(STDERR, "Error: [{$aiSection}] 섹션을 찾을 수 없습니다.\n");
        fwrite(STDERR, "사용 가능한 섹션: " . implode(', ', array_keys($allSections)) . "\n");
        exit(1);
    }
    $sectionsToCheck[$aiSection] = $allSections[$aiSection];
} else {
    $sectionsToCheck = $allSections;
}

// 결과 수집
$results = [];
$startTime = strtotime("-{$days} days");
$endTime = time();

foreach ($sectionsToCheck as $sectionName => $sectionConfig) {
    $provider = strtolower($sectionConfig['provider'] ?? '');

    if (!$verbose && !$jsonOutput) {
        echo "\n";
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
        echo "섹션: [{$sectionName}]\n";
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
    }

    $result = [
        'section' => $sectionName,
        'provider' => $provider,
        'model' => $sectionConfig['model'] ?? ptyAIConfig::getDefaultModel($provider),
        'status' => 'unknown',
        'data' => null,
        'error' => null,
    ];

    try {
        switch ($provider) {
            case 'anthropic':
                $result = array_merge($result, getAnthropicStats($sectionConfig, $startTime, $endTime, $verbose, $showDaily));
                break;

            case 'openai':
                $result = array_merge($result, getOpenAIStats($sectionConfig, $startTime, $endTime, $verbose, $showDaily, $days));
                break;

            case 'google':
                $result = array_merge($result, getGoogleStats($sectionConfig, $verbose));
                break;

            case 'ollama':
                $result = array_merge($result, getOllamaStats($sectionConfig, $verbose));
                break;

            default:
                $result['status'] = 'unsupported';
                $result['error'] = "지원되지 않는 provider: {$provider}";
        }
    } catch (\Exception $e) {
        $result['status'] = 'error';
        $result['error'] = $e->getMessage();
    }

    // 콘솔 출력 (JSON 모드가 아닐 때)
    if (!$jsonOutput) {
        printSectionResult($result, $verbose, $showDaily);
    }

    $results[] = $result;
}

// JSON 출력
if ($jsonOutput) {
    echo json_encode([
        'query' => [
            'start_time' => date('Y-m-d H:i:s', $startTime),
            'end_time' => date('Y-m-d H:i:s', $endTime),
            'days' => $days,
        ],
        'sections' => $results,
    ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
}

/**
 * Anthropic (Claude) 통계 조회
 * Admin API Key 필요 (sk-ant-admin...)
 * INI에서 adminApiKey 필드 또는 apiKey가 admin key인 경우 사용
 */
function getAnthropicStats($config, $startTime, $endTime, $verbose, $showDaily = false)
{
    $apiKey = trim($config['apiKey'] ?? '', '"\'');
    $adminApiKey = trim($config['adminApiKey'] ?? '', '"\'');
    $result = [
        'status' => 'ok',
        'data' => [],
    ];

    // Admin API Key 확인 (adminApiKey 필드 우선, 없으면 apiKey 확인)
    $effectiveAdminKey = null;
    if ($adminApiKey && strpos($adminApiKey, 'sk-ant-admin') === 0) {
        $effectiveAdminKey = $adminApiKey;
        $result['data']['key_type'] = 'admin (adminApiKey)';
    } elseif (strpos($apiKey, 'sk-ant-admin') === 0) {
        $effectiveAdminKey = $apiKey;
        $result['data']['key_type'] = 'admin (apiKey)';
    }

    if (!$effectiveAdminKey) {
        // Admin Key 없음: 연결 테스트만 수행
        $result['data']['key_type'] = 'standard';
        $result['data']['note'] = 'Admin API Key (sk-ant-admin...) 필요. INI에 adminApiKey 추가 또는 콘솔에서 확인: https://console.anthropic.com';
        $result['status'] = 'limited';
        return $result;
    }

    // Admin API로 사용량 조회
    // https://platform.claude.com/docs/en/build-with-claude/usage-cost-api
    // Usage endpoint: /v1/organizations/usage_report/messages
    $usageUrl = 'https://api.anthropic.com/v1/organizations/usage_report/messages';
    $params = [
        'starting_at' => date('Y-m-d\TH:i:s\Z', $startTime),
        'ending_at' => date('Y-m-d\TH:i:s\Z', $endTime),
        'group_by[]' => 'model',
    ];

    $response = curlRequest($usageUrl . '?' . http_build_query($params), [
        'x-api-key: ' . $effectiveAdminKey,
        'anthropic-version: 2023-06-01',
    ], $verbose);

    if ($response['http_code'] === 200 && $response['body']) {
        $data = json_decode($response['body'], true);
        $result['data']['usage'] = $data;

        // 요약 계산
        $summary = calculateAnthropicUsageSummary($data);
        if ($summary) {
            $result['data']['summary'] = $summary;
        }
    } else {
        $errorBody = json_decode($response['body'], true);
        $result['data']['usage_error'] = $errorBody['error']['message'] ?? "HTTP {$response['http_code']}";
    }

    // Cost API 호출
    // Cost endpoint: /v1/organizations/cost_report
    $costUrl = 'https://api.anthropic.com/v1/organizations/cost_report';
    $costParams = [
        'starting_at' => date('Y-m-d\TH:i:s\Z', $startTime),
        'ending_at' => date('Y-m-d\TH:i:s\Z', $endTime),
    ];

    $costResponse = curlRequest($costUrl . '?' . http_build_query($costParams), [
        'x-api-key: ' . $effectiveAdminKey,
        'anthropic-version: 2023-06-01',
    ], $verbose);

    if ($costResponse['http_code'] === 200 && $costResponse['body']) {
        $costData = json_decode($costResponse['body'], true);
        $result['data']['costs'] = $costData;

        // 비용 요약 계산
        $costSummary = calculateAnthropicCostSummary($costData);
        if ($costSummary) {
            $result['data']['cost_summary'] = $costSummary;
        }
    } else {
        $errorBody = json_decode($costResponse['body'], true);
        $result['data']['costs_error'] = $errorBody['error']['message'] ?? "HTTP {$costResponse['http_code']}";
    }

    return $result;
}

/**
 * Anthropic 사용량 요약 계산
 * 응답 구조: data[].results[].{model, input_tokens, output_tokens, ...}
 */
function calculateAnthropicUsageSummary($data)
{
    if (!isset($data['data']) || empty($data['data'])) {
        return null;
    }

    $totalInputTokens = 0;
    $totalOutputTokens = 0;
    $totalCacheCreationTokens = 0;
    $totalCacheReadTokens = 0;
    $modelUsage = [];

    // 중첩된 data[].results[] 구조 처리
    foreach ($data['data'] as $bucket) {
        if (!isset($bucket['results']) || empty($bucket['results'])) {
            continue;
        }
        foreach ($bucket['results'] as $item) {
            $model = $item['model'] ?? 'unknown';
            $input = $item['input_tokens'] ?? 0;
            $output = $item['output_tokens'] ?? 0;
            $cacheCreation = $item['cache_creation_input_tokens'] ?? 0;
            $cacheRead = $item['cache_read_input_tokens'] ?? 0;

            $totalInputTokens += $input;
            $totalOutputTokens += $output;
            $totalCacheCreationTokens += $cacheCreation;
            $totalCacheReadTokens += $cacheRead;

            if (!isset($modelUsage[$model])) {
                $modelUsage[$model] = ['input' => 0, 'output' => 0];
            }
            $modelUsage[$model]['input'] += $input;
            $modelUsage[$model]['output'] += $output;
        }
    }

    // 데이터가 없으면 null 반환
    if ($totalInputTokens === 0 && $totalOutputTokens === 0 && empty($modelUsage)) {
        return null;
    }

    return [
        'total_input_tokens' => $totalInputTokens,
        'total_output_tokens' => $totalOutputTokens,
        'total_tokens' => $totalInputTokens + $totalOutputTokens,
        'cache_creation_tokens' => $totalCacheCreationTokens,
        'cache_read_tokens' => $totalCacheReadTokens,
        'by_model' => $modelUsage,
    ];
}

/**
 * Anthropic 비용 요약 계산
 * 응답 구조: data[].results[].{amount_cents, ...}
 */
function calculateAnthropicCostSummary($data)
{
    if (!isset($data['data']) || empty($data['data'])) {
        return null;
    }

    $totalCost = 0.0;
    $hasData = false;

    // 중첩된 data[].results[] 구조 처리
    foreach ($data['data'] as $bucket) {
        if (!isset($bucket['results']) || empty($bucket['results'])) {
            continue;
        }
        $hasData = true;
        foreach ($bucket['results'] as $item) {
            // amount_cents 또는 amount 필드 확인 (cents 단위)
            $amountCents = $item['amount_cents'] ?? $item['amount'] ?? 0;
            $totalCost += floatval($amountCents) / 100;
        }
    }

    // 데이터가 없으면 null 반환
    if (!$hasData) {
        return null;
    }

    return [
        'total_usd' => round($totalCost, 4),
        'currency' => 'USD',
    ];
}

/**
 * OpenAI 통계 조회
 * adminApiKey가 있으면 사용, 없으면 apiKey 사용
 */
function getOpenAIStats($config, $startTime, $endTime, $verbose, $showDaily = false, $days = 30)
{
    $apiKey = trim($config['apiKey'] ?? '', '"\'');
    $adminApiKey = trim($config['adminApiKey'] ?? '', '"\'');
    $result = [
        'status' => 'ok',
        'data' => [],
    ];

    // Admin API Key 확인 (adminApiKey 우선)
    $effectiveKey = null;
    if ($adminApiKey && strpos($adminApiKey, 'sk-admin') === 0) {
        $effectiveKey = $adminApiKey;
        $result['data']['key_type'] = 'admin (adminApiKey)';
    } elseif ($apiKey) {
        $effectiveKey = $apiKey;
        $result['data']['key_type'] = 'standard (apiKey)';
    }

    if (!$effectiveKey) {
        $result['status'] = 'error';
        $result['error'] = 'API Key가 없습니다.';
        return $result;
    }

    // 모델 목록 조회
    $modelsUrl = 'https://api.openai.com/v1/models';
    $modelsResponse = curlRequest($modelsUrl, [
        'Authorization: Bearer ' . $effectiveKey,
    ], $verbose);

    if ($modelsResponse['http_code'] === 200 && $modelsResponse['body']) {
        $modelsData = json_decode($modelsResponse['body'], true);
        $modelNames = array_column($modelsData['data'] ?? [], 'id');
        sort($modelNames);
        $result['data']['available_models_count'] = count($modelNames);
        // GPT 관련 모델만 필터링
        $gptModels = array_filter($modelNames, function($m) {
            return preg_match('/^(gpt-|o1|o3|dall-e|whisper|tts|text-embedding)/i', $m);
        });
        $result['data']['main_models'] = array_values($gptModels);
    }

    // Usage API 호출 (completions)
    $usageUrl = 'https://api.openai.com/v1/organization/usage/completions';
    $params = [
        'start_time' => $startTime,
        'bucket_width' => '1d',
        'group_by' => ['model'],
        'limit' => $days + 1,  // 조회 기간만큼 버킷 요청
    ];

    $usageResponse = curlRequest($usageUrl . '?' . http_build_query($params), [
        'Authorization: Bearer ' . $effectiveKey,
        'Content-Type: application/json',
    ], $verbose);

    if ($usageResponse['http_code'] === 200 && $usageResponse['body']) {
        $usageData = json_decode($usageResponse['body'], true);
        $result['data']['usage'] = $usageData;

        // 요약 및 날짜별 계산
        $totalInputTokens = 0;
        $totalOutputTokens = 0;
        $totalRequests = 0;
        $dailyUsage = [];

        foreach ($usageData['data'] ?? [] as $bucket) {
            $date = isset($bucket['start_time']) ? date('Y-m-d', $bucket['start_time']) : null;
            $dayInput = 0;
            $dayOutput = 0;
            $dayRequests = 0;

            foreach ($bucket['results'] ?? [] as $r) {
                $input = $r['input_tokens'] ?? 0;
                $output = $r['output_tokens'] ?? 0;
                $requests = $r['num_model_requests'] ?? 0;

                $totalInputTokens += $input;
                $totalOutputTokens += $output;
                $totalRequests += $requests;

                $dayInput += $input;
                $dayOutput += $output;
                $dayRequests += $requests;
            }

            if ($date && ($dayInput > 0 || $dayOutput > 0 || $dayRequests > 0)) {
                $dailyUsage[$date] = [
                    'input_tokens' => $dayInput,
                    'output_tokens' => $dayOutput,
                    'requests' => $dayRequests,
                ];
            }
        }

        $result['data']['summary'] = [
            'total_input_tokens' => $totalInputTokens,
            'total_output_tokens' => $totalOutputTokens,
            'total_tokens' => $totalInputTokens + $totalOutputTokens,
            'total_requests' => $totalRequests,
        ];

        if ($showDaily && !empty($dailyUsage)) {
            krsort($dailyUsage);  // 최신 날짜 먼저
            $result['data']['daily_usage'] = $dailyUsage;
        }
    } else {
        $errorBody = json_decode($usageResponse['body'], true);
        $result['data']['usage_error'] = $errorBody['error']['message'] ?? "HTTP {$usageResponse['http_code']}";
    }

    // Costs API 호출
    $costsUrl = 'https://api.openai.com/v1/organization/costs';
    $costsParams = [
        'start_time' => $startTime,
        'bucket_width' => '1d',
        'limit' => $days + 1,  // 조회 기간만큼 버킷 요청
    ];

    $costsResponse = curlRequest($costsUrl . '?' . http_build_query($costsParams), [
        'Authorization: Bearer ' . $effectiveKey,
        'Content-Type: application/json',
    ], $verbose);

    if ($costsResponse['http_code'] === 200 && $costsResponse['body']) {
        $costsData = json_decode($costsResponse['body'], true);

        // 총 비용 및 날짜별 계산
        $totalCost = 0;
        $dailyCosts = [];

        foreach ($costsData['data'] ?? [] as $bucket) {
            $date = isset($bucket['start_time']) ? date('Y-m-d', $bucket['start_time']) : null;
            $dayCost = 0;

            foreach ($bucket['results'] ?? [] as $r) {
                $cost = floatval($r['amount']['value'] ?? 0);
                $totalCost += $cost;
                $dayCost += $cost;
            }

            if ($date && $dayCost > 0) {
                $dailyCosts[$date] = round($dayCost, 4);
            }
        }

        $result['data']['costs'] = [
            'total_usd' => round($totalCost, 4),
            'currency' => 'USD',
            'period_days' => round(($endTime - $startTime) / 86400),
        ];

        if ($showDaily && !empty($dailyCosts)) {
            krsort($dailyCosts);  // 최신 날짜 먼저
            $result['data']['daily_costs'] = $dailyCosts;
        }
    } else {
        $errorBody = json_decode($costsResponse['body'], true);
        $result['data']['costs_error'] = $errorBody['error']['message'] ?? "HTTP {$costsResponse['http_code']}";
    }

    // 잔액 조회는 API로 불가능 (브라우저 전용)
    // https://community.openai.com/t/openai-credit-balance-api/1280067
    $result['data']['balance_note'] = '잔액 확인: https://platform.openai.com/settings/organization/billing/overview';

    return $result;
}

/**
 * Google (Gemini) 통계 조회
 */
function getGoogleStats($config, $verbose)
{
    $apiKey = trim($config['apiKey'] ?? '', '"\'');
    $result = [
        'status' => 'ok',
        'data' => [],
    ];

    // 모델 목록 조회
    $modelsUrl = "https://generativelanguage.googleapis.com/v1beta/models?key={$apiKey}";
    $response = curlRequest($modelsUrl, [], $verbose);

    if ($response['http_code'] === 200 && $response['body']) {
        $data = json_decode($response['body'], true);
        $models = [];
        foreach ($data['models'] ?? [] as $model) {
            $models[] = [
                'name' => str_replace('models/', '', $model['name'] ?? ''),
                'displayName' => $model['displayName'] ?? '',
                'inputTokenLimit' => $model['inputTokenLimit'] ?? 0,
                'outputTokenLimit' => $model['outputTokenLimit'] ?? 0,
            ];
        }
        $result['data']['models'] = $models;
        $result['data']['models_count'] = count($models);
        $result['data']['note'] = '사용량 통계는 Google AI Studio에서 확인: https://aistudio.google.com';
    } else {
        $result['status'] = 'error';
        $errorBody = json_decode($response['body'], true);
        $result['error'] = $errorBody['error']['message'] ?? "HTTP {$response['http_code']}";
    }

    return $result;
}

/**
 * Ollama 통계 조회
 */
function getOllamaStats($config, $verbose)
{
    $apiUrl = rtrim(trim($config['apiUrl'] ?? 'http://localhost:11434', '"\''), '/');
    $result = [
        'status' => 'ok',
        'data' => [
            'server_url' => $apiUrl,
        ],
    ];

    // 모델 목록 조회
    $tagsUrl = "{$apiUrl}/api/tags";
    $tagsResponse = curlRequest($tagsUrl, [], $verbose);

    if ($tagsResponse['http_code'] === 200 && $tagsResponse['body']) {
        $tagsData = json_decode($tagsResponse['body'], true);
        $models = [];
        foreach ($tagsData['models'] ?? [] as $model) {
            $models[] = [
                'name' => $model['name'] ?? '',
                'size' => formatBytes($model['size'] ?? 0),
                'modified' => $model['modified_at'] ?? '',
                'family' => $model['details']['family'] ?? '',
                'parameter_size' => $model['details']['parameter_size'] ?? '',
                'quantization' => $model['details']['quantization_level'] ?? '',
            ];
        }
        $result['data']['models'] = $models;
        $result['data']['models_count'] = count($models);
    } else {
        $result['status'] = 'error';
        $result['error'] = $tagsResponse['error'] ?? "연결 실패 (HTTP {$tagsResponse['http_code']})";
        return $result;
    }

    // 실행 중인 모델 조회
    $psUrl = "{$apiUrl}/api/ps";
    $psResponse = curlRequest($psUrl, [], $verbose);

    if ($psResponse['http_code'] === 200 && $psResponse['body']) {
        $psData = json_decode($psResponse['body'], true);
        $running = [];
        foreach ($psData['models'] ?? [] as $model) {
            $running[] = [
                'name' => $model['name'] ?? '',
                'size' => formatBytes($model['size'] ?? 0),
                'vram' => formatBytes($model['size_vram'] ?? 0),
                'expires' => $model['expires_at'] ?? '',
            ];
        }
        $result['data']['running_models'] = $running;
        $result['data']['running_count'] = count($running);
    }

    return $result;
}

/**
 * cURL 요청 헬퍼
 */
function curlRequest($url, $headers = [], $verbose = false)
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    if (!empty($headers)) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }

    if ($verbose) {
        fwrite(STDERR, "━━━━━━━━━━━━ CURL REQUEST ━━━━━━━━━━━━\n");
        fwrite(STDERR, "URL: {$url}\n");
        if (!empty($headers)) {
            fwrite(STDERR, "Headers:\n");
            foreach ($headers as $h) {
                // API Key 마스킹
                if (preg_match('/^(Authorization|x-api-key):/i', $h)) {
                    $h = preg_replace('/([a-zA-Z0-9_-]{12})[a-zA-Z0-9_-]+/', '$1...', $h);
                }
                fwrite(STDERR, "  {$h}\n");
            }
        }
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
    }

    $body = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);

    if ($verbose) {
        fwrite(STDERR, "━━━━━━━━━━━━ CURL RESPONSE ━━━━━━━━━━━━\n");
        fwrite(STDERR, "HTTP Code: {$httpCode}\n");
        if ($error) {
            fwrite(STDERR, "Error: {$error}\n");
        }
        if ($body) {
            $prettyBody = json_decode($body, true);
            if ($prettyBody) {
                fwrite(STDERR, "Body:\n" . json_encode($prettyBody, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n");
            } else {
                fwrite(STDERR, "Body: {$body}\n");
            }
        }
        fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
    }

    return [
        'http_code' => $httpCode,
        'body' => $body,
        'error' => $error ?: null,
    ];
}

/**
 * 바이트 포맷팅
 */
function formatBytes($bytes)
{
    if ($bytes >= 1073741824) {
        return round($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return round($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return round($bytes / 1024, 2) . ' KB';
    }
    return $bytes . ' B';
}

/**
 * 섹션 결과 출력
 */
function printSectionResult($result, $verbose, $showDaily = false)
{
    $provider = $result['provider'];
    $model = $result['model'];
    $status = $result['status'];

    echo "Provider: {$provider}\n";
    echo "Model: {$model}\n";
    echo "Status: {$status}\n";

    if ($result['error']) {
        echo "Error: {$result['error']}\n";
    }

    if (!$result['data']) {
        return;
    }

    $data = $result['data'];

    switch ($provider) {
        case 'anthropic':
            if (isset($data['key_type'])) {
                echo "Key Type: {$data['key_type']}\n";
            }
            if (isset($data['note'])) {
                echo "Note: {$data['note']}\n";
            }
            // 요약 정보 출력
            if (isset($data['summary'])) {
                $s = $data['summary'];
                echo "\n[Usage Summary]\n";
                echo "  Input Tokens: " . number_format($s['total_input_tokens']) . "\n";
                echo "  Output Tokens: " . number_format($s['total_output_tokens']) . "\n";
                echo "  Total Tokens: " . number_format($s['total_tokens']) . "\n";
                if ($s['cache_creation_tokens'] > 0 || $s['cache_read_tokens'] > 0) {
                    echo "  Cache Creation: " . number_format($s['cache_creation_tokens']) . "\n";
                    echo "  Cache Read: " . number_format($s['cache_read_tokens']) . "\n";
                }
                if (!empty($s['by_model'])) {
                    echo "\n[By Model]\n";
                    foreach ($s['by_model'] as $model => $usage) {
                        $in = number_format($usage['input']);
                        $out = number_format($usage['output']);
                        echo "  {$model}: in={$in}, out={$out}\n";
                    }
                }
            } elseif (!isset($data['usage_error'])) {
                echo "\n[Usage Summary]\n";
                echo "  (조회 기간 내 사용 데이터 없음)\n";
            }
            // 비용 요약
            if (isset($data['cost_summary'])) {
                $c = $data['cost_summary'];
                echo "\n[Costs]\n";
                echo "  Total: \${$c['total_usd']} {$c['currency']}\n";
            } elseif (!isset($data['costs_error'])) {
                echo "\n[Costs]\n";
                echo "  (조회 기간 내 비용 데이터 없음)\n";
            }
            if (isset($data['usage_error'])) {
                echo "Usage Error: {$data['usage_error']}\n";
            }
            if (isset($data['costs_error'])) {
                echo "Costs Error: {$data['costs_error']}\n";
            }
            break;

        case 'openai':
            if (isset($data['key_type'])) {
                echo "Key Type: {$data['key_type']}\n";
            }
            if (isset($data['available_models_count'])) {
                echo "Available Models: {$data['available_models_count']}\n";
            }
            if (isset($data['summary'])) {
                $s = $data['summary'];
                echo "\n[Usage Summary]\n";
                echo "  Total Requests: " . number_format($s['total_requests']) . "\n";
                echo "  Input Tokens: " . number_format($s['total_input_tokens']) . "\n";
                echo "  Output Tokens: " . number_format($s['total_output_tokens']) . "\n";
                echo "  Total Tokens: " . number_format($s['total_tokens']) . "\n";
            }
            // 날짜별 사용량
            if ($showDaily && isset($data['daily_usage']) && !empty($data['daily_usage'])) {
                echo "\n[Daily Usage]\n";
                echo "  Date         Requests      Input Tokens    Output Tokens\n";
                echo "  ──────────────────────────────────────────────────────────\n";
                foreach ($data['daily_usage'] as $date => $usage) {
                    $req = str_pad(number_format($usage['requests']), 10, ' ', STR_PAD_LEFT);
                    $in = str_pad(number_format($usage['input_tokens']), 15, ' ', STR_PAD_LEFT);
                    $out = str_pad(number_format($usage['output_tokens']), 15, ' ', STR_PAD_LEFT);
                    echo "  {$date}  {$req}  {$in}  {$out}\n";
                }
            }
            if (isset($data['costs'])) {
                $c = $data['costs'];
                echo "\n[Costs]\n";
                echo "  Total: \${$c['total_usd']} USD ({$c['period_days']} days)\n";
            }
            // 날짜별 비용
            if ($showDaily && isset($data['daily_costs']) && !empty($data['daily_costs'])) {
                echo "\n[Daily Costs]\n";
                foreach ($data['daily_costs'] as $date => $cost) {
                    echo "  {$date}: \${$cost} USD\n";
                }
            }
            if (isset($data['usage_error'])) {
                echo "Usage Error: {$data['usage_error']}\n";
            }
            if (isset($data['costs_error'])) {
                echo "Costs Error: {$data['costs_error']}\n";
            }
            if (isset($data['balance_note'])) {
                echo "\n[Balance]\n";
                echo "  {$data['balance_note']}\n";
            }
            break;

        case 'google':
            if (isset($data['models_count'])) {
                echo "Available Models: {$data['models_count']}\n";
            }
            if (isset($data['models']) && !empty($data['models'])) {
                echo "\n[Models]\n";
                foreach ($data['models'] as $m) {
                    $inputLimit = number_format($m['inputTokenLimit']);
                    $outputLimit = number_format($m['outputTokenLimit']);
                    echo "  - {$m['name']} (in:{$inputLimit}, out:{$outputLimit})\n";
                }
            }
            if (isset($data['note'])) {
                echo "\nNote: {$data['note']}\n";
            }
            break;

        case 'ollama':
            if (isset($data['server_url'])) {
                echo "Server: {$data['server_url']}\n";
            }
            if (isset($data['models_count'])) {
                echo "Installed Models: {$data['models_count']}\n";
            }
            if (isset($data['models']) && !empty($data['models'])) {
                echo "\n[Installed Models]\n";
                foreach ($data['models'] as $m) {
                    $info = "{$m['name']} ({$m['size']}";
                    if ($m['parameter_size']) {
                        $info .= ", {$m['parameter_size']}";
                    }
                    if ($m['quantization']) {
                        $info .= ", {$m['quantization']}";
                    }
                    $info .= ")";
                    echo "  - {$info}\n";
                }
            }
            if (isset($data['running_count'])) {
                echo "\nRunning Models: {$data['running_count']}\n";
                if (!empty($data['running_models'])) {
                    foreach ($data['running_models'] as $m) {
                        echo "  - {$m['name']} (VRAM: {$m['vram']})\n";
                    }
                }
            }
            break;
    }
}

/**
 * 사용량 테이블 출력 (Anthropic)
 */
function printUsageTable($usage)
{
    if (!isset($usage['data']) || empty($usage['data'])) {
        echo "  (데이터 없음)\n";
        return;
    }

    foreach ($usage['data'] as $item) {
        $model = $item['model'] ?? 'unknown';
        $inputTokens = number_format($item['input_tokens'] ?? 0);
        $outputTokens = number_format($item['output_tokens'] ?? 0);
        echo "  {$model}: in={$inputTokens}, out={$outputTokens}\n";
    }
}

/**
 * 비용 테이블 출력 (Anthropic)
 */
function printCostTable($costs)
{
    if (!isset($costs['data']) || empty($costs['data'])) {
        echo "  (데이터 없음)\n";
        return;
    }

    $total = 0;
    foreach ($costs['data'] as $item) {
        $amount = floatval($item['amount'] ?? 0) / 100;  // cents to USD
        $total += $amount;
    }

    echo "  Total: \$" . number_format($total, 4) . " USD\n";
}
