<?php
/**
 * Google Cloud Speech-to-Text API 엔드포인트
 * 오디오 파일을 받아서 텍스트로 변환
 */

// 타임아웃 설정 (504 오류 방지)
ini_set('max_execution_time', 120); // 120초
set_time_limit(60); // PHP 실행 시간 60초로 제한

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');

require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");

// 권한 체크
if ($level > 5) {
    echo json_encode([
        'success' => false,
        'error' => '접근 권한이 없습니다.'
    ]);
    exit;
}

// 세션 쓰기 닫기 (이후 긴 작업 시 세션 잠금 방지)
session_write_close();

// POST 요청만 허용
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode([
        'success' => false,
        'error' => 'POST 요청만 허용됩니다.'
    ]);
    exit;
}

// 오디오 파일 확인
if (!isset($_FILES['audio']) || $_FILES['audio']['error'] !== UPLOAD_ERR_OK) {
    echo json_encode([
        'success' => false,
        'error' => '오디오 파일이 전송되지 않았습니다.'
    ]);
    exit;
}

$audioFile = $_FILES['audio'];
$audioPath = $audioFile['tmp_name'];
$audioType = $audioFile['type'];

// 오디오 파일 유효성 검사
$allowedTypes = ['audio/webm', 'audio/wav', 'audio/ogg', 'audio/mp3', 'audio/mpeg', 'audio/x-flac'];
if (!in_array($audioType, $allowedTypes)) {
    echo json_encode([
        'success' => false,
        'error' => '지원하지 않는 오디오 형식입니다. (webm, wav, ogg, mp3, flac 지원)'
    ]);
    exit;
}

// Google Cloud Speech-to-Text API 설정
$googleApiKey = '';
$accessToken = null; // 서비스 계정용 OAuth 토큰
$useServiceAccount = false;
$googleApiUrl = 'https://speech.googleapis.com/v1/speech:recognize';

// API 키 파일 경로 (우선순위 순)
// 상대 경로와 절대 경로 모두 확인
$docRoot = $_SERVER['DOCUMENT_ROOT'];
$apiKeyPaths = [
    $docRoot . '/5130/apikey/google_api.txt',
    $docRoot . '/apikey/google_api.txt',
    dirname($docRoot) . '/5130/apikey/google_api.txt', // 상위 디렉토리에서 확인
    dirname($docRoot) . '/apikey/google_api.txt',
    __DIR__ . '/../../apikey/google_api.txt', // 현재 파일 기준 상대 경로
    __DIR__ . '/../../../apikey/google_api.txt',
    $docRoot . '/5130/config/google_speech_api.php',
    $docRoot . '/config/google_speech_api.php',
];

// 서비스 계정 파일 경로
$serviceAccountPaths = [
    $docRoot . '/5130/apikey/google_service_account.json',
    $docRoot . '/apikey/google_service_account.json',
    dirname($docRoot) . '/5130/apikey/google_service_account.json',
    dirname($docRoot) . '/apikey/google_service_account.json',
    __DIR__ . '/../../apikey/google_service_account.json',
    __DIR__ . '/../../../apikey/google_service_account.json',
];

// API 키 파일에서 읽기
$foundKeyPath = null;
$checkedPaths = [];

foreach ($apiKeyPaths as $keyPath) {
    $checkedPaths[] = $keyPath . ' (exists: ' . (file_exists($keyPath) ? 'yes' : 'no') . ')';
    
    if (file_exists($keyPath)) {
        $foundKeyPath = $keyPath;
        if (pathinfo($keyPath, PATHINFO_EXTENSION) === 'php') {
            // PHP 설정 파일인 경우
            require_once($keyPath);
            if (isset($GOOGLE_SPEECH_API_KEY)) {
                $googleApiKey = trim($GOOGLE_SPEECH_API_KEY);
                break;
            }
        } else {
            // 텍스트 파일인 경우 (google_api.txt)
            $keyContent = file_get_contents($keyPath);
            $googleApiKey = trim($keyContent);
            
            // 빈 줄이나 주석 제거
            $lines = explode("\n", $googleApiKey);
            $googleApiKey = '';
            foreach ($lines as $line) {
                $line = trim($line);
                if (!empty($line) && !preg_match('/^#/', $line)) {
                    $googleApiKey = $line;
                    break;
                }
            }
            
            if (!empty($googleApiKey)) {
                break;
            }
        }
    }
}

// 서비스 계정 파일 찾기
$serviceAccountPath = null;
foreach ($serviceAccountPaths as $saPath) {
    if (file_exists($saPath)) {
        $serviceAccountPath = $saPath;
        break;
    }
}

// OAuth 2.0 토큰 생성 함수 (서비스 계정용)
function getServiceAccountToken($serviceAccountPath) {
    if (!file_exists($serviceAccountPath)) {
        return null;
    }
    
    $serviceAccount = json_decode(file_get_contents($serviceAccountPath), true);
    if (!$serviceAccount || !isset($serviceAccount['private_key']) || !isset($serviceAccount['client_email'])) {
        return null;
    }
    
    // Base64 URL 인코딩 함수
    $base64UrlEncode = function($data) {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    };
    
    // JWT 생성
    $now = time();
    
    // JWT 헤더
    $jwtHeader = [
        'alg' => 'RS256',
        'typ' => 'JWT'
    ];
    
    // JWT 클레임
    $jwtClaim = [
        'iss' => $serviceAccount['client_email'],
        'scope' => 'https://www.googleapis.com/auth/cloud-platform',
        'aud' => 'https://oauth2.googleapis.com/token',
        'exp' => $now + 3600,
        'iat' => $now
    ];
    
    $encodedHeader = $base64UrlEncode(json_encode($jwtHeader));
    $encodedClaim = $base64UrlEncode(json_encode($jwtClaim));
    
    // 서명 생성
    $privateKey = openssl_pkey_get_private($serviceAccount['private_key']);
    if (!$privateKey) {
        return null;
    }
    
    $signature = '';
    $signData = $encodedHeader . '.' . $encodedClaim;
    if (!openssl_sign($signData, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
        openssl_free_key($privateKey);
        return null;
    }
    openssl_free_key($privateKey);
    
    $encodedSignature = $base64UrlEncode($signature);
    $jwt = $encodedHeader . '.' . $encodedClaim . '.' . $encodedSignature;
    
    // OAuth 2.0 토큰 요청
    $tokenCh = curl_init('https://oauth2.googleapis.com/token');
    curl_setopt($tokenCh, CURLOPT_POST, true);
    curl_setopt($tokenCh, CURLOPT_POSTFIELDS, http_build_query([
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' => $jwt
    ]));
    curl_setopt($tokenCh, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($tokenCh, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
    // 타임아웃 설정
    curl_setopt($tokenCh, CURLOPT_TIMEOUT, 30); // 30초
    curl_setopt($tokenCh, CURLOPT_CONNECTTIMEOUT, 10); // 연결 타임아웃 10초
    
    $tokenResponse = curl_exec($tokenCh);
    $tokenHttpCode = curl_getinfo($tokenCh, CURLINFO_HTTP_CODE);
    curl_close($tokenCh);
    
    if ($tokenHttpCode === 200) {
        $tokenData = json_decode($tokenResponse, true);
        if (isset($tokenData['access_token'])) {
            return $tokenData['access_token'];
        }
    }
    
    return null;
}

// API 키가 없거나 형식이 잘못된 경우 서비스 계정 시도
if (empty($googleApiKey) || strlen($googleApiKey) < 20) {
    if ($serviceAccountPath) {
        $accessToken = getServiceAccountToken($serviceAccountPath);
        if ($accessToken) {
            $useServiceAccount = true;
        }
    }
    
    if (!$useServiceAccount) {
        echo json_encode([
            'success' => false,
            'error' => 'Google Cloud Speech-to-Text API 인증 정보가 없습니다.',
            'hint' => 'API 키 파일 또는 서비스 계정 파일을 찾을 수 없습니다.',
            'checked_paths' => $checkedPaths,
            'service_account_path' => $serviceAccountPath,
            'document_root' => $docRoot,
            'current_dir' => __DIR__
        ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
        exit;
    }
}

// API 키 형식 확인 (Google API 키는 보통 AIza로 시작)
$isValidFormat = (strpos($googleApiKey, 'AIza') === 0 || strlen($googleApiKey) >= 35);
if (!$isValidFormat && !$useServiceAccount) {
    // API 키 형식이 잘못된 경우 서비스 계정 시도
    if ($serviceAccountPath) {
        $accessToken = getServiceAccountToken($serviceAccountPath);
        if ($accessToken) {
            $useServiceAccount = true;
            $googleApiKey = ''; // API 키 사용 안 함
        }
    }
}

// 서비스 계정이 있으면 우선 사용 (API 키보다 안정적)
// API 키는 간헐적으로 오류가 발생할 수 있으므로 서비스 계정을 기본으로 사용
if (!$useServiceAccount && $serviceAccountPath && file_exists($serviceAccountPath)) {
    $accessToken = getServiceAccountToken($serviceAccountPath);
    if ($accessToken) {
        $useServiceAccount = true;
        // API 키는 백업으로 유지하되 서비스 계정 우선 사용
        error_log('Using service account for authentication (more reliable than API key)');
    }
}

// API 키 디버깅 정보
$debugInfo = [
    'api_key_path' => $foundKeyPath,
    'api_key_length' => strlen($googleApiKey),
    'api_key_prefix' => !empty($googleApiKey) ? substr($googleApiKey, 0, 10) . '...' : null,
    'api_key_suffix' => !empty($googleApiKey) ? '...' . substr($googleApiKey, -5) : null,
    'use_service_account' => $useServiceAccount,
    'service_account_path' => $serviceAccountPath,
    'document_root' => $docRoot,
    'checked_paths' => $checkedPaths
];

try {
    // 오디오 파일을 base64로 인코딩
    $audioContent = file_get_contents($audioPath);
    $audioBase64 = base64_encode($audioContent);
    
    // 오디오 형식에 따른 encoding 설정
    $encoding = 'WEBM_OPUS';
    $sampleRate = 16000; // 기본값
    
    if (strpos($audioType, 'wav') !== false) {
        $encoding = 'LINEAR16';
        $sampleRate = 16000;
    } elseif (strpos($audioType, 'ogg') !== false) {
        $encoding = 'OGG_OPUS';
        $sampleRate = 48000; // Opus는 보통 48kHz
    } elseif (strpos($audioType, 'flac') !== false) {
        $encoding = 'FLAC';
        $sampleRate = 16000;
    } elseif (strpos($audioType, 'webm') !== false) {
        $encoding = 'WEBM_OPUS';
        $sampleRate = 48000; // WebM Opus는 보통 48kHz
    }
    
    // Google Cloud Speech-to-Text API 요청 데이터
    $requestData = [
        'config' => [
            'encoding' => $encoding,
            'sampleRateHertz' => $sampleRate,
            'languageCode' => 'ko-KR',
            'enableAutomaticPunctuation' => true,
            'enableWordTimeOffsets' => false,
            'model' => 'latest_long', // 긴 오디오에 적합
            'alternativeLanguageCodes' => ['ko'], // 추가 언어 코드
        ],
        'audio' => [
            'content' => $audioBase64
        ]
    ];
    
    // 디버깅 정보 (개발 환경에서만)
    if (isset($_GET['debug'])) {
        error_log('Google Speech API Request: ' . json_encode([
            'encoding' => $encoding,
            'sampleRate' => $sampleRate,
            'audioSize' => strlen($audioBase64),
            'audioType' => $audioType
        ]));
    }
    
    // cURL로 API 호출
    $headers = ['Content-Type: application/json'];
    $apiUrl = $googleApiUrl;
    
    if ($useServiceAccount && $accessToken) {
        // 서비스 계정 사용: Bearer 토큰 사용
        $headers[] = 'Authorization: Bearer ' . $accessToken;
    } else if (!empty($googleApiKey)) {
        // API 키 사용: 쿼리 파라미터로 전달
        $apiUrl = $googleApiUrl . '?key=' . urlencode($googleApiKey);
    } else {
        throw new Exception('인증 정보가 없습니다. API 키 또는 서비스 계정이 필요합니다.');
    }
    
    $ch = curl_init($apiUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    // 타임아웃 설정 (504 오류 방지)
    curl_setopt($ch, CURLOPT_TIMEOUT, 50); // 50초
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 연결 타임아웃 10초
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);
    curl_close($ch);
    
    if ($curlError) {
        throw new Exception('cURL 오류: ' . $curlError);
    }
    
    if ($httpCode !== 200) {
        $errorData = json_decode($response, true);
        $errorMessage = 'API 오류 (HTTP ' . $httpCode . ')';
        $debugInfo = [];
        
        if (isset($errorData['error'])) {
            $errorMessage .= ': ' . ($errorData['error']['message'] ?? '알 수 없는 오류');
            $debugInfo['error_details'] = $errorData['error'];
            
            // API 키 오류인 경우 서비스 계정으로 재시도
            if (isset($errorData['error']['message']) && 
                (stripos($errorData['error']['message'], 'API key') !== false || 
                 stripos($errorData['error']['message'], 'not valid') !== false ||
                 stripos($errorData['error']['message'], 'invalid') !== false ||
                 stripos($errorData['error']['message'], 'unauthorized') !== false)) {
                
                // 서비스 계정으로 재시도
                if ($serviceAccountPath && file_exists($serviceAccountPath)) {
                    // 서비스 계정을 사용 중이었는데도 오류가 발생하면 토큰 재생성
                    if ($useServiceAccount) {
                        error_log('Service account token may have expired, regenerating...');
                    }
                    
                    $accessToken = getServiceAccountToken($serviceAccountPath);
                    if ($accessToken) {
                        // 서비스 계정으로 재시도
                        $headers = [
                            'Content-Type: application/json',
                            'Authorization: Bearer ' . $accessToken
                        ];
                        
                        $ch = curl_init($googleApiUrl);
                        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                        curl_setopt($ch, CURLOPT_POST, true);
                        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
                        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
                        // 타임아웃 설정 (504 오류 방지)
                        curl_setopt($ch, CURLOPT_TIMEOUT, 50); // 50초
                        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 연결 타임아웃 10초
                        
                        $response = curl_exec($ch);
                        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                        curl_close($ch);
                        
                        if ($httpCode === 200) {
                            // 서비스 계정으로 성공
                            $result = json_decode($response, true);
                            if (isset($result['results']) && count($result['results']) > 0) {
                                $transcript = '';
                                foreach ($result['results'] as $resultItem) {
                                    if (isset($resultItem['alternatives'][0]['transcript'])) {
                                        $transcript .= $resultItem['alternatives'][0]['transcript'] . ' ';
                                    }
                                }
                                
                                $transcript = trim($transcript);
                                
                                echo json_encode([
                                    'success' => true,
                                    'transcript' => $transcript,
                                    'confidence' => isset($result['results'][0]['alternatives'][0]['confidence']) 
                                        ? $result['results'][0]['alternatives'][0]['confidence'] 
                                        : null,
                                    'auth_method' => 'service_account',
                                    'retry_success' => true
                                ]);
                                exit;
                            }
                        }
                    }
                }
                
                // 재시도 실패 시 상세 안내
                $errorMessage .= "\n\n⚠️ API 키 오류 해결 방법:\n";
                $errorMessage .= "1. Google Cloud Console (https://console.cloud.google.com/) 접속\n";
                $errorMessage .= "2. 프로젝트 선택: codebridge-chatbot\n";
                $errorMessage .= "3. 'API 및 서비스' > '라이브러리'에서 'Cloud Speech-to-Text API' 검색 및 활성화\n";
                $errorMessage .= "4. 'API 및 서비스' > '사용자 인증 정보'에서 API 키 확인\n";
                $errorMessage .= "5. API 키 제한 설정에서 'Cloud Speech-to-Text API' 허용 확인\n";
                $errorMessage .= "\n현재 API 키 파일: " . ($foundKeyPath ?? 'N/A');
                $errorMessage .= "\nAPI 키 길이: " . strlen($googleApiKey) . " 문자";
                if ($serviceAccountPath) {
                    $errorMessage .= "\n서비스 계정 파일: " . $serviceAccountPath;
                }
            }
        } else {
            $errorMessage .= ': ' . substr($response, 0, 200);
        }
        
        // 디버그 정보에 API 키 정보 추가
        $debugInfo['api_key_info'] = [
            'path' => $foundKeyPath,
            'length' => strlen($googleApiKey),
            'prefix' => !empty($googleApiKey) ? substr($googleApiKey, 0, 10) . '...' : null,
            'suffix' => !empty($googleApiKey) ? '...' . substr($googleApiKey, -5) : null,
            'format_valid' => !empty($googleApiKey) ? (strpos($googleApiKey, 'AIza') === 0 || strlen($googleApiKey) >= 35) : false,
            'use_service_account' => $useServiceAccount,
            'service_account_path' => $serviceAccountPath
        ];
        
        if (isset($_GET['debug'])) {
            $debugInfo['full_response'] = $response;
            $debugInfo['request_url'] = $useServiceAccount ? $googleApiUrl : ($googleApiUrl . '?key=' . substr($googleApiKey, 0, 10) . '...');
        }
        
        throw new Exception($errorMessage);
    }
    
    $result = json_decode($response, true);
    
    // 결과 처리
    if (isset($result['results']) && count($result['results']) > 0) {
        $transcript = '';
        foreach ($result['results'] as $resultItem) {
            if (isset($resultItem['alternatives'][0]['transcript'])) {
                $transcript .= $resultItem['alternatives'][0]['transcript'] . ' ';
            }
        }
        
        $transcript = trim($transcript);
        
        echo json_encode([
            'success' => true,
            'transcript' => $transcript,
            'confidence' => isset($result['results'][0]['alternatives'][0]['confidence']) 
                ? $result['results'][0]['alternatives'][0]['confidence'] 
                : null,
            'auth_method' => $useServiceAccount ? 'service_account' : 'api_key'
        ]);
    } else {
        echo json_encode([
            'success' => false,
            'error' => '음성을 인식할 수 없었습니다.',
            'debug' => $result
        ]);
    }
    
} catch (Exception $e) {
    $errorResponse = [
        'success' => false,
        'error' => $e->getMessage()
    ];
    
    // 항상 API 키 정보 포함 (보안을 위해 일부만 표시)
    $errorResponse['debug'] = [
        'api_key_path' => $foundKeyPath ?? null,
        'api_key_length' => isset($googleApiKey) ? strlen($googleApiKey) : 0,
        'api_key_prefix' => isset($googleApiKey) ? substr($googleApiKey, 0, 10) . '...' : null,
        'api_key_suffix' => isset($googleApiKey) ? '...' . substr($googleApiKey, -5) : null,
        'api_key_format' => isset($googleApiKey) ? (strpos($googleApiKey, 'AIza') === 0 ? 'Google API Key (AIza...)' : 'Other format') : 'N/A',
        'use_service_account' => isset($useServiceAccount) ? $useServiceAccount : false,
        'service_account_path' => isset($serviceAccountPath) ? $serviceAccountPath : null,
        'document_root' => $docRoot ?? null,
        'checked_paths_count' => count($checkedPaths ?? [])
    ];
    
    // 상세 디버그 모드일 때 추가 정보
    if (isset($_GET['debug'])) {
        $errorResponse['debug']['exception_class'] = get_class($e);
        $errorResponse['debug']['file'] = $e->getFile();
        $errorResponse['debug']['line'] = $e->getLine();
        $errorResponse['debug']['checked_paths'] = $checkedPaths ?? [];
    }
    
    echo json_encode($errorResponse, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}

