<?php

namespace App\Services\Video;

use App\Services\GoogleCloudService;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class VeoVideoService
{
    private GoogleCloudService $googleCloud;

    private string $projectId;

    private string $location;

    public function __construct(GoogleCloudService $googleCloud)
    {
        $this->googleCloud = $googleCloud;
        $this->projectId = config('services.vertex_ai.project_id', 'codebridge-chatbot');
        $this->location = config('services.vertex_ai.location', 'us-central1');
    }

    /**
     * 프롬프트 → 영상 클립 생성 요청 (비동기)
     *
     * @return array|null ['operationName' => '...'] or null
     */
    public function generateClip(string $prompt, int $duration = 8): ?array
    {
        $token = $this->googleCloud->getAccessToken();
        if (! $token) {
            Log::error('VeoVideoService: 액세스 토큰 획득 실패');

            return null;
        }

        try {
            $url = "https://{$this->location}-aiplatform.googleapis.com/v1/projects/{$this->projectId}/locations/{$this->location}/publishers/google/models/veo-3.1-generate-preview:predictLongRunning";

            // 한국인 여성 등장인물 프롬프트 프리픽스 추가
            $characterPrefix = 'Featuring a young Korean woman in her 20s with natural black hair. ';
            $fullPrompt = $characterPrefix.$prompt;

            $response = Http::withToken($token)
                ->timeout(60)
                ->post($url, [
                    'instances' => [
                        [
                            'prompt' => $fullPrompt,
                        ],
                    ],
                    'parameters' => [
                        'aspectRatio' => '9:16',
                        'duration' => "{$duration}s",
                        'resolution' => '720p',
                        'personGeneration' => 'allow_adult',
                        'generateAudio' => false,
                        'sampleCount' => 1,
                    ],
                ]);

            if (! $response->successful()) {
                Log::error('VeoVideoService: 영상 생성 요청 실패', [
                    'status' => $response->status(),
                    'body' => $response->body(),
                ]);

                return null;
            }

            $data = $response->json();
            $operationName = $data['name'] ?? null;

            if (! $operationName) {
                Log::error('VeoVideoService: Operation name 없음', ['response' => $data]);

                return null;
            }

            Log::info('VeoVideoService: 영상 생성 요청 성공', [
                'operationName' => $operationName,
                'prompt' => substr($fullPrompt, 0, 150),
            ]);

            return ['operationName' => $operationName];
        } catch (\Exception $e) {
            Log::error('VeoVideoService: 영상 생성 예외', ['error' => $e->getMessage()]);

            return null;
        }
    }

    /**
     * 비동기 작업 상태 확인 (fetchPredictOperation 엔드포인트 사용)
     *
     * @return array ['done' => bool, 'video' => base64|null, 'error' => string|null]
     */
    public function checkOperation(string $operationName): array
    {
        $token = $this->googleCloud->getAccessToken();
        if (! $token) {
            return ['done' => false, 'video' => null, 'error' => '토큰 획득 실패'];
        }

        try {
            // Veo 전용: fetchPredictOperation POST 엔드포인트 사용
            $model = $this->getModelFromOperation($operationName);
            $url = "https://{$this->location}-aiplatform.googleapis.com/v1/projects/{$this->projectId}/locations/{$this->location}/publishers/google/models/{$model}:fetchPredictOperation";

            $response = Http::withToken($token)->timeout(30)->post($url, [
                'operationName' => $operationName,
            ]);

            if (! $response->successful()) {
                Log::warning('VeoVideoService: 상태 확인 HTTP 오류', [
                    'status' => $response->status(),
                    'body' => substr($response->body(), 0, 500),
                ]);

                return ['done' => false, 'video' => null, 'error' => 'HTTP '.$response->status()];
            }

            $data = $response->json();

            if (! ($data['done'] ?? false)) {
                return ['done' => false, 'video' => null, 'error' => null];
            }

            if (isset($data['error'])) {
                return ['done' => true, 'video' => null, 'error' => $data['error']['message'] ?? 'Unknown error'];
            }

            // 영상 데이터 추출 (response.videos[].bytesBase64Encoded)
            $videos = $data['response']['videos'] ?? [];
            if (empty($videos)) {
                return ['done' => true, 'video' => null, 'error' => '영상 데이터 없음 (RAI 필터링 가능)'];
            }

            $videoBase64 = $videos[0]['bytesBase64Encoded'] ?? null;

            return ['done' => true, 'video' => $videoBase64, 'error' => $videoBase64 ? null : 'Base64 데이터 없음'];
        } catch (\Exception $e) {
            Log::error('VeoVideoService: 상태 확인 예외', ['error' => $e->getMessage()]);

            return ['done' => false, 'video' => null, 'error' => $e->getMessage()];
        }
    }

    /**
     * Operation 이름에서 모델명 추출
     */
    private function getModelFromOperation(string $operationName): string
    {
        // "projects/.../models/veo-3.1-generate-preview/operations/..." → "veo-3.1-generate-preview"
        if (preg_match('/models\/([^\/]+)\/operations/', $operationName, $matches)) {
            return $matches[1];
        }

        return 'veo-3.1-generate-preview';
    }

    /**
     * 영상 생성 완료까지 폴링 대기
     *
     * @return array ['path' => string|null, 'error' => string|null]
     */
    public function waitAndSave(string $operationName, string $savePath, int $maxAttempts = 120): array
    {
        $consecutiveErrors = 0;

        for ($i = 0; $i < $maxAttempts; $i++) {
            sleep(10);

            $result = $this->checkOperation($operationName);

            // 완료 + 에러 → 생성 실패 (원인 반환)
            if ($result['error'] && $result['done']) {
                Log::error('VeoVideoService: 영상 생성 실패', ['error' => $result['error']]);

                return ['path' => null, 'error' => $result['error']];
            }

            // 미완료 + HTTP 에러 → 연속 에러 카운트
            if ($result['error'] && ! $result['done']) {
                $consecutiveErrors++;
                Log::warning('VeoVideoService: 폴링 오류', [
                    'attempt' => $i + 1,
                    'error' => $result['error'],
                    'consecutiveErrors' => $consecutiveErrors,
                ]);

                if ($consecutiveErrors >= 5) {
                    Log::error('VeoVideoService: 연속 5회 폴링 실패로 중단', [
                        'operationName' => $operationName,
                    ]);

                    return ['path' => null, 'error' => '연속 폴링 실패: '.$result['error']];
                }

                continue;
            }

            // 에러 없으면 카운터 초기화
            $consecutiveErrors = 0;

            // 완료 + 영상 데이터 있음 → 저장
            if ($result['done'] && $result['video']) {
                $videoData = base64_decode($result['video']);
                $dir = dirname($savePath);

                if (! is_dir($dir)) {
                    mkdir($dir, 0755, true);
                }

                file_put_contents($savePath, $videoData);

                Log::info('VeoVideoService: 영상 저장 완료', [
                    'path' => $savePath,
                    'size' => strlen($videoData),
                ]);

                return ['path' => $savePath, 'error' => null];
            }

            // 진행 중 로그 (30초 간격)
            if (($i + 1) % 3 === 0) {
                Log::info('VeoVideoService: 영상 생성 대기 중', [
                    'attempt' => $i + 1,
                    'elapsed' => ($i + 1) * 10 .'초',
                ]);
            }
        }

        Log::error('VeoVideoService: 영상 생성 타임아웃', [
            'operationName' => $operationName,
            'attempts' => $maxAttempts,
        ]);

        return ['path' => null, 'error' => '타임아웃 ('.($maxAttempts * 10).'초)'];
    }
}
