<?php

namespace App\Http\Controllers\Video;

use App\Http\Controllers\Controller;
use App\Jobs\VideoGenerationJob;
use App\Models\VideoGeneration;
use App\Services\GoogleCloudStorageService;
use App\Services\Video\GeminiScriptService;
use App\Services\Video\TrendingKeywordService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

class Veo3Controller extends Controller
{
    public function __construct(
        private readonly GeminiScriptService $geminiService,
        private readonly GoogleCloudStorageService $gcsService,
        private readonly TrendingKeywordService $trendingService
    ) {}

    /**
     * 메인 페이지
     */
    public function index(Request $request): View|Response
    {
        if ($request->header('HX-Request')) {
            return response('', 200)->header('HX-Redirect', route('video.veo3.index'));
        }

        return view('video.veo3.index');
    }

    /**
     * 실시간 급상승 키워드 목록 (건강 채널용 필터링)
     */
    public function fetchTrending(): JsonResponse
    {
        // 1단계: 원본 트렌딩 키워드 수집 (자체 캐시 있음)
        $rawKeywords = $this->trendingService->fetchTrendingKeywords(20);

        if (empty($rawKeywords)) {
            return response()->json([
                'success' => false,
                'keywords' => [],
                'reason' => 'rss_fail',
                'message' => 'Google 트렌드 데이터를 가져올 수 없습니다. 잠시 후 다시 시도해주세요.',
            ]);
        }

        // 2단계: Gemini 필터링 (성공 결과만 캐시)
        $cached = Cache::get('health_trending');
        if ($cached !== null && ! empty($cached)) {
            return response()->json([
                'success' => true,
                'keywords' => $cached,
            ]);
        }

        // 직접 필터링 시도
        $healthKeywords = $this->geminiService->filterHealthTrending($rawKeywords);

        // 건강 키워드가 없으면 리프레이밍 폴백 시도
        if (empty($healthKeywords)) {
            $healthKeywords = $this->geminiService->reframeAsHealthTrending($rawKeywords);
        }

        if (! empty($healthKeywords)) {
            Cache::put('health_trending', $healthKeywords, 1800);

            return response()->json([
                'success' => true,
                'keywords' => $healthKeywords,
            ]);
        }

        // 최종 폴백: 원본 키워드 상위 5개를 건강 없이 반환
        $fallback = collect($rawKeywords)->take(5)->map(fn ($item) => [
            'keyword' => $item['keyword'],
            'health_angle' => '',
            'suggested_topic' => $item['keyword'],
            'traffic' => $item['traffic'] ?? '',
            'news_title' => $item['news_title'] ?? '',
            'pub_date' => $item['pub_date'] ?? null,
            'is_raw' => true,
        ])->values()->toArray();

        return response()->json([
            'success' => true,
            'keywords' => $fallback,
            'reason' => 'no_health_match',
            'message' => '건강 관련 트렌딩이 없어 인기 키워드를 표시합니다.',
        ]);
    }

    /**
     * 키워드 → 제목 후보 생성 (trending_context 옵션 지원)
     */
    public function generateTitles(Request $request): JsonResponse
    {
        $request->validate([
            'keyword' => 'required|string|max:100',
            'trending_context' => 'nullable|array',
        ]);

        $keyword = $request->input('keyword');
        $trendingContext = $request->input('trending_context');

        if ($trendingContext) {
            $titles = $this->geminiService->generateTrendingHookTitles($keyword, $trendingContext);
        } else {
            $titles = $this->geminiService->generateTrendingTitles($keyword);
        }

        if (empty($titles)) {
            return response()->json([
                'success' => false,
                'message' => '제목 생성에 실패했습니다. API 키를 확인해주세요.',
            ], 500);
        }

        // DB에 pending 레코드 생성
        $video = VideoGeneration::create([
            'tenant_id' => session('selected_tenant_id'),
            'user_id' => auth()->id(),
            'keyword' => $keyword,
            'status' => VideoGeneration::STATUS_TITLES_GENERATED,
        ]);

        return response()->json([
            'success' => true,
            'video_id' => $video->id,
            'titles' => $titles,
        ]);
    }

    /**
     * 시나리오 생성 (제목 선택 후)
     */
    public function generateScenario(Request $request): JsonResponse
    {
        $request->validate([
            'video_id' => 'required|integer',
            'title' => 'required|string|max:500',
        ]);

        $video = VideoGeneration::findOrFail($request->input('video_id'));
        $title = $request->input('title');

        $scenario = $this->geminiService->generateScenario($title, $video->keyword);

        if (empty($scenario) || empty($scenario['scenes'])) {
            return response()->json([
                'success' => false,
                'message' => '시나리오 생성에 실패했습니다.',
            ], 500);
        }

        $video->update([
            'title' => $title,
            'scenario' => $scenario,
            'status' => VideoGeneration::STATUS_SCENARIO_READY,
        ]);

        return response()->json([
            'success' => true,
            'video_id' => $video->id,
            'scenario' => $scenario,
        ]);
    }

    /**
     * 영상 생성 시작 (Job 디스패치)
     */
    public function generate(Request $request): JsonResponse
    {
        $request->validate([
            'video_id' => 'required|integer',
            'scenario' => 'nullable|array',
        ]);

        $video = VideoGeneration::findOrFail($request->input('video_id'));

        // 이미 생성 중이면 거부
        if (in_array($video->status, [
            VideoGeneration::STATUS_GENERATING_TTS,
            VideoGeneration::STATUS_GENERATING_CLIPS,
            VideoGeneration::STATUS_GENERATING_BGM,
            VideoGeneration::STATUS_ASSEMBLING,
        ])) {
            return response()->json([
                'success' => false,
                'message' => '이미 영상을 생성 중입니다.',
            ], 409);
        }

        $customScenario = $request->input('scenario');

        if ($customScenario) {
            $video->update(['scenario' => $customScenario]);
        }

        $video->updateProgress(VideoGeneration::STATUS_PENDING, 0, '대기 중...');

        VideoGenerationJob::dispatch($video->id, $video->title, $customScenario ?? $video->scenario);

        return response()->json([
            'success' => true,
            'video_id' => $video->id,
            'message' => '영상 생성이 시작되었습니다.',
        ]);
    }

    /**
     * 진행 상태 폴링
     */
    public function status(int $id): JsonResponse
    {
        $video = VideoGeneration::findOrFail($id);

        return response()->json([
            'id' => $video->id,
            'status' => $video->status,
            'progress' => $video->progress,
            'current_step' => $video->current_step,
            'error_message' => $video->error_message,
            'output_path' => $video->output_path ? true : false,
            'cost_usd' => $video->cost_usd,
            'updated_at' => $video->updated_at?->toIso8601String(),
            'created_at' => $video->created_at?->toIso8601String(),
        ]);
    }

    /**
     * 완성 영상 다운로드
     */
    public function download(int $id): BinaryFileResponse|RedirectResponse|JsonResponse
    {
        $video = VideoGeneration::findOrFail($id);

        if ($video->status !== VideoGeneration::STATUS_COMPLETED || ! $video->output_path) {
            return response()->json(['message' => '아직 영상이 완성되지 않았습니다.'], 404);
        }

        // GCS 서명URL로 리다이렉트
        if ($video->gcs_path && $this->gcsService->isAvailable()) {
            $signedUrl = $this->gcsService->getSignedUrl($video->gcs_path, 30);
            if ($signedUrl) {
                return redirect()->away($signedUrl);
            }
        }

        // 로컬 파일 폴백
        if (! file_exists($video->output_path)) {
            return response()->json(['message' => '영상 파일을 찾을 수 없습니다.'], 404);
        }

        $filename = "shorts_{$video->keyword}_{$video->id}.mp4";
        $filename = preg_replace('/[^a-zA-Z0-9가-힣_\-.]/', '_', $filename);

        return response()->download($video->output_path, $filename, [
            'Content-Type' => 'video/mp4',
        ]);
    }

    /**
     * 영상 미리보기 (스트리밍)
     */
    public function preview(int $id): Response|RedirectResponse|JsonResponse
    {
        $video = VideoGeneration::findOrFail($id);

        // GCS 서명URL로 리다이렉트
        if ($video->gcs_path && $this->gcsService->isAvailable()) {
            $signedUrl = $this->gcsService->getSignedUrl($video->gcs_path, 60);
            if ($signedUrl) {
                return redirect()->away($signedUrl);
            }
        }

        // 로컬 파일 폴백
        if (! $video->output_path || ! file_exists($video->output_path)) {
            return response()->json(['message' => '영상 파일을 찾을 수 없습니다.'], 404);
        }

        $path = $video->output_path;
        $size = filesize($path);

        return response()->file($path, [
            'Content-Type' => 'video/mp4',
            'Content-Length' => $size,
            'Accept-Ranges' => 'bytes',
        ]);
    }

    /**
     * 생성 이력 상세 (시나리오, 프롬프트, YouTube 텍스트 등)
     */
    public function show(int $id): JsonResponse
    {
        $video = VideoGeneration::where('user_id', auth()->id())->findOrFail($id);

        $scenario = $video->scenario ?? [];
        $scenes = $scenario['scenes'] ?? [];

        // YouTube Shorts 텍스트 생성 (완료된 영상만)
        $youtubeText = null;
        if ($video->status === VideoGeneration::STATUS_COMPLETED) {
            $youtubeText = $this->buildYoutubeText($video, $scenario, $scenes);
        }

        return response()->json([
            'success' => true,
            'data' => [
                'id' => $video->id,
                'keyword' => $video->keyword,
                'title' => $video->title,
                'status' => $video->status,
                'progress' => $video->progress,
                'current_step' => $video->current_step,
                'error_message' => $video->error_message,
                'cost_usd' => $video->cost_usd,
                'created_at' => $video->created_at?->toIso8601String(),
                'updated_at' => $video->updated_at?->toIso8601String(),
                'scenario' => $scenario,
                'scenes' => array_map(function ($scene) {
                    return [
                        'scene_number' => $scene['scene_number'] ?? null,
                        'scene_type' => $scene['scene_type'] ?? null,
                        'narration' => $scene['narration'] ?? '',
                        'visual_prompt' => $scene['visual_prompt'] ?? '',
                        'duration' => $scene['duration'] ?? 0,
                        'mood' => $scene['mood'] ?? '',
                    ];
                }, $scenes),
                'clips_data' => $video->clips_data,
                'youtube_text' => $youtubeText,
            ],
        ]);
    }

    /**
     * YouTube Shorts 제목 + 설명 텍스트 빌드
     */
    private function buildYoutubeText(VideoGeneration $video, array $scenario, array $scenes): array
    {
        $title = $video->title ?? '';
        $keyword = $video->keyword ?? '';

        // 해시태그 생성
        $hashtags = ['#shorts', '#쇼츠'];
        if ($keyword) {
            $hashtags[] = '#'.str_replace(' ', '', $keyword);
        }
        // 시나리오에서 추가 태그 추출
        $bgmMood = $scenario['bgm_mood'] ?? '';
        if ($bgmMood) {
            $hashtags[] = '#'.$bgmMood;
        }
        $hashtags = array_merge($hashtags, ['#건강', '#건강정보', '#헬스']);

        // 설명란 텍스트
        $descLines = [];
        $descLines[] = $title;
        $descLines[] = '';

        // 핵심 내용 요약 (나레이션에서 추출)
        foreach ($scenes as $scene) {
            $narration = $scene['narration'] ?? '';
            if ($narration && ($scene['scene_type'] ?? '') !== 'HOOK') {
                $descLines[] = '- '.mb_substr($narration, 0, 60);
            }
        }

        $descLines[] = '';
        $descLines[] = implode(' ', array_unique($hashtags));

        return [
            'title' => $title,
            'description' => implode("\n", $descLines),
            'hashtags' => array_unique($hashtags),
        ];
    }

    /**
     * 생성 이력 목록
     */
    public function history(Request $request): JsonResponse
    {
        $videos = VideoGeneration::where('user_id', auth()->id())
            ->orderByDesc('created_at')
            ->limit(50)
            ->get(['id', 'keyword', 'title', 'status', 'progress', 'cost_usd', 'created_at', 'updated_at']);

        return response()->json([
            'success' => true,
            'data' => $videos,
        ]);
    }

    /**
     * 생성 이력 삭제 (복수)
     */
    public function destroy(Request $request): JsonResponse
    {
        $request->validate([
            'ids' => 'required|array|min:1',
            'ids.*' => 'integer',
        ]);

        $videos = VideoGeneration::where('user_id', auth()->id())
            ->whereIn('id', $request->input('ids'))
            ->get();

        $deleted = 0;
        foreach ($videos as $video) {
            // GCS 파일 삭제
            if ($video->gcs_path && $this->gcsService->isAvailable()) {
                $this->gcsService->delete($video->gcs_path);
            }

            // 로컬 작업 디렉토리 삭제 (클립, 나레이션, 최종 영상 등)
            $workDir = storage_path("app/video_gen/{$video->id}");
            if (is_dir($workDir)) {
                $files = glob("{$workDir}/*");
                foreach ($files as $file) {
                    if (is_file($file)) {
                        @unlink($file);
                    }
                }
                @rmdir($workDir);
            }

            $video->delete();
            $deleted++;
        }

        return response()->json([
            'success' => true,
            'deleted' => $deleted,
        ]);
    }
}
