<?php

namespace platyFramework;

require_once(__DIR__ . "/../ptycommon/model.php");

/**
 * VoyageAI API Model
 * VoyageAI 임베딩 API를 사용하기 위한 클래스
 *
 * 참고: VoyageAI는 임베딩 전용 API입니다. 텍스트 생성(get/getSimple)은 지원하지 않습니다.
 */
class VoyageAPIModel extends model
{
    private $apiKey;
    private $model = 'voyage-3-large';
    private $apiUrl = 'https://api.voyageai.com/v1/embeddings';
    private $debug = false;

    /**
     * 생성자
     * @param string $apiKey VoyageAI API 키
     */
    public function __construct($apiKey = null)
    {
        parent::__construct();
        $this->apiKey = $apiKey;
    }

    /**
     * API 키 설정
     * @param string $apiKey
     * @return $this
     */
    public function setAPIKey($apiKey)
    {
        $this->apiKey = $apiKey;
        return $this;
    }

    /**
     * 모델 설정
     * @param string $model 사용할 VoyageAI 모델명
     * @return $this
     */
    public function setModel($model)
    {
        $this->model = $model;
        return $this;
    }

    /**
     * 디버그 모드 설정
     * @param bool $debug 디버그 모드 활성화 여부
     * @return $this
     */
    public function setDebug($debug)
    {
        $this->debug = $debug;
        return $this;
    }

    /**
     * 텍스트 생성 API (미지원)
     * VoyageAI는 임베딩 전용 API이므로 텍스트 생성을 지원하지 않습니다.
     *
     * @param string $message
     * @return false
     */
    public function get($message)
    {
        error_log("VoyageAI는 텍스트 생성을 지원하지 않습니다. getEmbedding()을 사용하세요.");
        return false;
    }

    /**
     * 간단한 텍스트 응답 (미지원)
     * @param string $message
     * @return false
     */
    public function getSimple($message)
    {
        return false;
    }

    /**
     * 응답에서 텍스트 추출 (미지원)
     * @param array $response
     * @return false
     */
    public function extractText($response)
    {
        return false;
    }

    /**
     * 텍스트 임베딩 API 호출
     * @param string|array $text 임베딩할 텍스트 (단일 문자열 또는 배열)
     * @param string $model 임베딩 모델 (기본값: voyage-3-large)
     * @param string|null $inputType 입력 유형 (query, document, null)
     * @return array|false ['embedding' => [...], 'usage' => N] 또는 false
     */
    public function getEmbedding($text, $model = null, $inputType = null)
    {
        if ($model === null) {
            $model = $this->model;
        }

        // 단일 문자열을 배열로 변환
        $input = is_array($text) ? $text : array($text);

        $data = array(
            'input' => $input,
            'model' => $model,
        );

        // input_type 추가 (query: 검색 쿼리, document: 저장할 문서)
        if ($inputType !== null) {
            $data['input_type'] = $inputType;
        }

        $headers = array(
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->apiKey,
        );

        // 디버그 출력
        if ($this->debug) {
            fwrite(STDERR, "━━━━━━━━━━━━ CURL REQUEST ━━━━━━━━━━━━\n");
            fwrite(STDERR, "URL: {$this->apiUrl}\n");
            fwrite(STDERR, "Method: POST\n");
            fwrite(STDERR, "Headers:\n");
            foreach ($headers as $header) {
                if (strpos($header, 'Authorization:') === 0) {
                    $key = substr($this->apiKey, 0, 12) . '...';
                    fwrite(STDERR, "  Authorization: Bearer {$key}\n");
                } else {
                    fwrite(STDERR, "  {$header}\n");
                }
            }
            fwrite(STDERR, "Body:\n");
            fwrite(STDERR, "  " . json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n");
            fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
        }

        $ch = curl_init($this->apiUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

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

        // 디버그 출력 (응답)
        if ($this->debug) {
            fwrite(STDERR, "━━━━━━━━━━━━ CURL RESPONSE ━━━━━━━━━━━━\n");
            fwrite(STDERR, "HTTP Code: {$httpCode}\n");
            if ($error) {
                fwrite(STDERR, "cURL Error: {$error}\n");
            }
            fwrite(STDERR, "Response:\n");
            $prettyResponse = json_decode($response, true);
            if ($prettyResponse) {
                if (isset($prettyResponse['data'][0]['embedding'])) {
                    $prettyResponse['data'][0]['embedding'] = '[' . count($prettyResponse['data'][0]['embedding']) . ' dimensions...]';
                }
                fwrite(STDERR, "  " . json_encode($prettyResponse, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n");
            } else {
                fwrite(STDERR, "  {$response}\n");
            }
            fwrite(STDERR, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
        }

        if ($error) {
            error_log("VoyageAI Embedding API cURL Error: " . $error);
            return false;
        }

        if ($httpCode !== 200) {
            error_log("VoyageAI Embedding API HTTP Error: " . $httpCode . " - " . $response);
            return false;
        }

        $result = json_decode($response, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            error_log("VoyageAI Embedding API JSON Decode Error: " . json_last_error_msg());
            return false;
        }

        if (!isset($result['data'][0]['embedding'])) {
            return false;
        }

        return array(
            'response' => $result,
            'embedding' => $result['data'][0]['embedding'],
            'usage' => isset($result['usage']['total_tokens']) ? $result['usage']['total_tokens'] : null,
            '_raw' => $result,
        );
    }

    /**
     * 여러 텍스트의 임베딩을 한 번에 얻기
     * @param array $texts 임베딩할 텍스트 배열
     * @param string $model 임베딩 모델
     * @param string|null $inputType 입력 유형
     * @return array|false ['embeddings' => [[...], [...]], 'usage' => N] 또는 false
     */
    public function getEmbeddings($texts, $model = null, $inputType = null)
    {
        if ($model === null) {
            $model = $this->model;
        }

        $data = array(
            'input' => $texts,
            'model' => $model,
        );

        if ($inputType !== null) {
            $data['input_type'] = $inputType;
        }

        $headers = array(
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->apiKey,
        );

        $ch = curl_init($this->apiUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

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

        if ($error) {
            error_log("VoyageAI Embedding API cURL Error: " . $error);
            return false;
        }

        if ($httpCode !== 200) {
            error_log("VoyageAI Embedding API HTTP Error: " . $httpCode . " - " . $response);
            return false;
        }

        $result = json_decode($response, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            error_log("VoyageAI Embedding API JSON Decode Error: " . json_last_error_msg());
            return false;
        }

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

        $embeddings = array();
        foreach ($result['data'] as $item) {
            $embeddings[] = $item['embedding'];
        }

        return array(
            'response' => $result,
            'embeddings' => $embeddings,
            'usage' => isset($result['usage']['total_tokens']) ? $result['usage']['total_tokens'] : null,
            '_raw' => $result,
        );
    }
}
