@extends('layouts.app')

@section('title', 'YouTube Shorts AI 생성기')

@push('styles')
<style>
    .step-badge {
        display: inline-flex; align-items: center; justify-content: center;
        width: 2rem; height: 2rem; border-radius: 9999px; font-size: 0.875rem; font-weight: 700;
    }
    .step-active { background: #4f46e5; color: #fff; }
    .step-done { background: #22c55e; color: #fff; }
    .step-pending { background: #e5e7eb; color: #6b7280; }
    .scene-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 1rem; margin-bottom: 0.75rem; box-shadow: 0 1px 2px rgba(0,0,0,.05); }
    .progress-bar { height: 0.75rem; border-radius: 9999px; transition: all 0.5s ease-out; }
    .title-option {
        border: 2px solid #e5e7eb; border-radius: 0.75rem; padding: 1rem; cursor: pointer;
        transition: all 0.2s ease; position: relative; background: #fff;
    }
    .title-option:hover { border-color: #818cf8; background: #eef2ff; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(79,70,229,.1); }
    .title-option.selected {
        border-color: #4f46e5; background: #eef2ff;
        box-shadow: 0 0 0 3px rgba(79,70,229,.15), 0 4px 12px rgba(79,70,229,.1);
    }
    .title-option .radio-dot {
        width: 1.25rem; height: 1.25rem; border-radius: 9999px; border: 2px solid #d1d5db;
        display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.2s ease;
    }
    .title-option:hover .radio-dot { border-color: #818cf8; }
    .title-option.selected .radio-dot { border-color: #4f46e5; background: #4f46e5; }
    .title-option.selected .radio-dot::after {
        content: ''; width: 0.5rem; height: 0.5rem; border-radius: 9999px; background: #fff;
    }
    .title-option .check-badge {
        position: absolute; top: -0.5rem; right: -0.5rem; width: 1.5rem; height: 1.5rem;
        background: #4f46e5; border-radius: 9999px; display: none;
        align-items: center; justify-content: center; color: #fff; font-size: 0.75rem;
    }
    .title-option.selected .check-badge { display: flex; }
    .fade-in { animation: fadeIn 0.3s ease-in; }
    @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
    @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
</style>
@endpush

@section('content')
<meta name="csrf-token" content="{{ csrf_token() }}">
<div id="veo3-root"></div>
@endsection

@push('scripts')
@include('partials.react-cdn')
@verbatim
<script type="text/babel">
const { useState, useEffect, useCallback, useRef } = React;

const CSRF = document.querySelector('meta[name="csrf-token"]')?.content;

const api = (url, options = {}) => {
    return fetch(url, {
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-TOKEN': CSRF,
            'Accept': 'application/json',
            ...options.headers,
        },
        ...options,
    }).then(async (res) => {
        const data = await res.json();
        if (!res.ok) throw new Error(data.message || `HTTP ${res.status}`);
        return data;
    });
};

// ============================================================
// Step Indicator
// ============================================================
const StepIndicator = ({ currentStep }) => {
    const steps = [
        { num: 1, label: '키워드 입력' },
        { num: 2, label: '제목 선택' },
        { num: 3, label: '시나리오 확인' },
        { num: 4, label: '영상 생성' },
        { num: 5, label: '완성' },
    ];

    return (
        <div className="flex items-center justify-center gap-2 mb-8">
            {steps.map((step, i) => (
                <React.Fragment key={step.num}>
                    <div className="flex flex-col items-center">
                        <div className={`step-badge ${currentStep > step.num ? 'step-done' : currentStep === step.num ? 'step-active' : 'step-pending'}`}>
                            {currentStep > step.num ? '✓' : step.num}
                        </div>
                        <span className={`text-xs mt-1 ${currentStep >= step.num ? 'text-indigo-600 font-medium' : 'text-gray-400'}`}>
                            {step.label}
                        </span>
                    </div>
                    {i < steps.length - 1 && (
                        <div className={`w-12 h-0.5 mt-[-12px] ${currentStep > step.num ? 'bg-green-500' : 'bg-gray-200'}`} />
                    )}
                </React.Fragment>
            ))}
        </div>
    );
};

// ============================================================
// Step 1: Keyword Input
// ============================================================
const KeywordInput = ({ onSubmit, loading }) => {
    const [keyword, setKeyword] = useState('');
    const [trendingKeywords, setTrendingKeywords] = useState([]);
    const [trendingLoading, setTrendingLoading] = useState(false);
    const [trendingContext, setTrendingContext] = useState(null);
    const [trendingError, setTrendingError] = useState('');
    const inputRef = useRef(null);

    useEffect(() => { inputRef.current?.focus(); }, []);

    const handleSubmit = (e) => {
        e.preventDefault();
        if (keyword.trim()) onSubmit(keyword.trim(), trendingContext);
    };

    const [trendingInfo, setTrendingInfo] = useState('');

    const fetchTrending = async () => {
        setTrendingLoading(true);
        setTrendingError('');
        setTrendingInfo('');
        try {
            const data = await api('/video/veo3/trending');
            setTrendingKeywords(data.keywords || []);
            if ((data.keywords || []).length === 0) {
                setTrendingError(data.message || '트렌딩 키워드를 가져오지 못했습니다.');
            } else if (data.reason === 'no_health_match') {
                setTrendingInfo(data.message || '건강 관련 트렌딩이 없어 인기 키워드를 표시합니다.');
            }
        } catch (err) {
            setTrendingError(err.message || '네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
        } finally {
            setTrendingLoading(false);
        }
    };

    const selectTrending = (item) => {
        setKeyword(item.suggested_topic || item.keyword);
        setTrendingContext({
            keyword: item.keyword,
            news_title: item.news_title,
            traffic: item.traffic,
            pub_date: item.pub_date,
            health_angle: item.health_angle || '',
            suggested_topic: item.suggested_topic || '',
        });
        inputRef.current?.focus();
    };

    return (
        <div className="fade-in max-w-lg mx-auto">
            <div className="text-center mb-6">
                <h2 className="text-2xl font-bold text-gray-800">키워드를 입력하세요</h2>
                <p className="text-gray-500 mt-2">AI가 건강 채널용 YouTube Shorts 제목을 생성합니다</p>
            </div>

            {/* Trending Button */}
            <div className="text-center mb-4">
                <button
                    type="button"
                    onClick={fetchTrending}
                    disabled={trendingLoading}
                    className="inline-flex items-center gap-2 px-4 py-2 border border-green-300 bg-green-50 text-green-700 rounded-lg text-sm font-medium hover:bg-green-100 hover:border-green-400 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                >
                    {trendingLoading ? (
                        <>
                            <svg className="animate-spin h-4 w-4" viewBox="0 0 24 24"><circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none"/><path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/></svg>
                            불러오는 중...
                        </>
                    ) : (
                        <>
                            <span>&#128154;</span>
                            건강 트렌드 자동추출
                        </>
                    )}
                </button>
            </div>

            {/* Trending Error */}
            {trendingError && (
                <div className="mb-4 text-center text-sm text-red-500">{trendingError}</div>
            )}

            {/* Trending Info (non-error message) */}
            {trendingInfo && !trendingError && (
                <div className="mb-4 text-center text-sm text-amber-600 bg-amber-50 py-2 px-3 rounded-lg border border-amber-200">{trendingInfo}</div>
            )}

            {/* Trending Keyword Chips */}
            {trendingKeywords.length > 0 && (
                <div className="mb-5 p-3 bg-gray-50 rounded-lg border border-gray-200">
                    <div className="text-xs text-gray-500 mb-2 font-medium">
                        {trendingKeywords.some(k => k.is_raw) ? '🔥 실시간 인기 키워드 (클릭하여 선택)' : trendingKeywords.some(k => k.is_reframed) ? '💡 트렌드 × 건강 키워드 (클릭하여 선택)' : '\u{1F49A} 건강 트렌드 키워드 (클릭하여 선택)'}
                    </div>
                    <div className="flex flex-wrap gap-2">
                        {trendingKeywords.map((item, i) => {
                            const isSelected = trendingContext?.keyword === item.keyword;
                            return (
                                <button
                                    key={i}
                                    type="button"
                                    onClick={() => selectTrending(item)}
                                    className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm transition-all cursor-pointer border ${
                                        isSelected
                                            ? 'bg-green-600 text-white border-green-600 shadow-sm'
                                            : 'bg-white text-gray-700 border-gray-300 hover:border-green-400 hover:bg-green-50'
                                    }`}
                                >
                                    <span className="font-medium">{item.keyword}</span>
                                    {item.health_angle && (
                                        <span className={`text-xs px-1.5 py-0.5 rounded-full ${
                                            isSelected ? 'bg-green-500 text-green-100' : 'bg-green-100 text-green-600'
                                        }`}>
                                            {item.health_angle}
                                        </span>
                                    )}
                                    {!item.health_angle && item.traffic && (
                                        <span className={`text-xs ${isSelected ? 'text-green-200' : 'text-gray-400'}`}>
                                            {item.traffic}
                                        </span>
                                    )}
                                </button>
                            );
                        })}
                    </div>
                </div>
            )}

            <form onSubmit={handleSubmit} className="flex gap-3">
                <input
                    ref={inputRef}
                    type="text"
                    value={keyword}
                    onChange={(e) => {
                        setKeyword(e.target.value);
                        if (trendingContext && e.target.value !== (trendingContext.suggested_topic || trendingContext.keyword)) {
                            setTrendingContext(null);
                        }
                    }}
                    placeholder="예: 다이어트, 주식투자, 여행..."
                    className="flex-1 border border-gray-300 rounded-lg px-4 py-3 text-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
                    maxLength={100}
                    disabled={loading}
                />
                <button
                    type="submit"
                    disabled={!keyword.trim() || loading}
                    className="bg-indigo-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                >
                    {loading ? (
                        <span className="flex items-center gap-2">
                            <svg className="animate-spin h-5 w-5" viewBox="0 0 24 24"><circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none"/><path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/></svg>
                            생성 중...
                        </span>
                    ) : '제목 생성'}
                </button>
            </form>
        </div>
    );
};

// ============================================================
// Step 2: Title Selection
// ============================================================
const TitleSelection = ({ titles, onSelect, onBack, loading }) => {
    const [selectedIdx, setSelectedIdx] = useState(null);

    return (
        <div className="fade-in max-w-lg mx-auto">
            <div className="text-center mb-6">
                <h2 className="text-2xl font-bold text-gray-800">제목을 선택하세요</h2>
                <p className="text-gray-500 mt-2">클릭하여 마음에 드는 제목을 선택합니다</p>
            </div>
            <div className="space-y-3 mb-6">
                {titles.map((item, i) => (
                    <div
                        key={i}
                        className={`title-option ${selectedIdx === i ? 'selected' : ''}`}
                        onClick={() => setSelectedIdx(i)}
                    >
                        <div className="check-badge">✓</div>
                        <div className="flex items-start gap-3">
                            <div className="radio-dot mt-0.5"><span /></div>
                            <div className="flex-1">
                                <div className="font-medium text-gray-800">{item.title}</div>
                                <div className="text-sm text-gray-500 mt-1">{item.hook}</div>
                            </div>
                            <div className="text-xs text-gray-400 mt-1 flex-shrink-0">#{i + 1}</div>
                        </div>
                    </div>
                ))}
            </div>
            <div className="flex gap-3">
                <button
                    onClick={onBack}
                    className="px-4 py-2 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50"
                >
                    뒤로
                </button>
                <button
                    onClick={() => selectedIdx !== null && onSelect(titles[selectedIdx].title)}
                    disabled={selectedIdx === null || loading}
                    className="flex-1 bg-indigo-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                >
                    {loading ? '시나리오 생성 중...' : '이 제목으로 시나리오 생성'}
                </button>
            </div>
        </div>
    );
};

// ============================================================
// Step 3: Scenario Preview & Edit
// ============================================================
const ScenarioPreview = ({ scenario, onGenerate, onBack, loading }) => {
    const [scenes, setScenes] = useState(scenario.scenes || []);
    const [bgmMood, setBgmMood] = useState(scenario.bgm_mood || 'upbeat');

    const updateScene = (idx, field, value) => {
        const updated = [...scenes];
        updated[idx] = { ...updated[idx], [field]: value };
        setScenes(updated);
    };

    const totalDuration = scenes.reduce((sum, s) => sum + (s.duration || 0), 0);

    const handleGenerate = () => {
        onGenerate({ ...scenario, scenes, bgm_mood: bgmMood, total_duration: totalDuration });
    };

    return (
        <div className="fade-in max-w-2xl mx-auto">
            <div className="text-center mb-6">
                <h2 className="text-2xl font-bold text-gray-800">시나리오 미리보기</h2>
                <p className="text-gray-500 mt-2">
                    "{scenario.title}" | 총 {totalDuration}초 | {scenes.length}개 장면
                </p>
            </div>

            <div className="space-y-3 mb-6">
                {scenes.map((scene, i) => (
                    <div key={i} className="scene-card">
                        <div className="flex items-center justify-between mb-2">
                            <span className="text-sm font-bold text-indigo-600">
                                장면 {scene.scene_number} ({scene.duration}초)
                            </span>
                            <span className="text-xs px-2 py-1 bg-gray-100 rounded-full text-gray-500">
                                {scene.mood}
                            </span>
                        </div>
                        <div className="mb-2">
                            <label className="text-xs text-gray-500 font-medium">나레이션 (자막)</label>
                            <textarea
                                value={scene.narration}
                                onChange={(e) => updateScene(i, 'narration', e.target.value)}
                                className="w-full border border-gray-200 rounded p-2 text-sm mt-1 resize-none"
                                rows={2}
                            />
                        </div>
                        <div>
                            <label className="text-xs text-gray-500 font-medium">영상 프롬프트 (영어)</label>
                            <textarea
                                value={scene.visual_prompt}
                                onChange={(e) => updateScene(i, 'visual_prompt', e.target.value)}
                                className="w-full border border-gray-200 rounded p-2 text-sm mt-1 resize-none font-mono"
                                rows={3}
                            />
                        </div>
                    </div>
                ))}
            </div>

            <div className="mb-6 p-3 bg-gray-50 rounded-lg">
                <label className="text-sm font-medium text-gray-600">BGM 분위기</label>
                <input
                    type="text"
                    value={bgmMood}
                    onChange={(e) => setBgmMood(e.target.value)}
                    className="w-full border border-gray-200 rounded p-2 text-sm mt-1"
                    placeholder="upbeat, energetic, calm..."
                />
            </div>

            <div className="bg-amber-50 border border-amber-200 rounded-lg p-3 mb-6 text-sm text-amber-700">
                예상 비용: ~$7.72 (Veo 3.1 Fast 기준) | 소요 시간: 약 10~20분
            </div>

            <div className="flex gap-3">
                <button
                    onClick={onBack}
                    className="px-4 py-2 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50"
                >
                    뒤로
                </button>
                <button
                    onClick={handleGenerate}
                    disabled={loading}
                    className="flex-1 bg-green-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                >
                    {loading ? '요청 중...' : '영상 생성 시작'}
                </button>
            </div>
        </div>
    );
};

// ============================================================
// Step 4: Progress (경과 시간 + 멈춤 감지 + 타임라인)
// ============================================================
const STEP_LABELS = {
    pending: { icon: '⏳', label: 'Queue 대기', order: 0 },
    scenario_ready: { icon: '📝', label: '시나리오 생성', order: 1 },
    generating_tts: { icon: '🎙️', label: '나레이션 생성', order: 2 },
    generating_clips: { icon: '🎬', label: '영상 클립 생성', order: 3 },
    generating_bgm: { icon: '🎵', label: 'BGM 준비', order: 4 },
    assembling: { icon: '🔧', label: '최종 합성', order: 5 },
    completed: { icon: '✅', label: '완료', order: 6 },
    failed: { icon: '❌', label: '실패', order: -1 },
};

const formatElapsed = (seconds) => {
    if (seconds < 60) return `${seconds}초`;
    const m = Math.floor(seconds / 60);
    const s = seconds % 60;
    return `${m}분 ${s}초`;
};

const GenerationProgress = ({ videoId }) => {
    const [status, setStatus] = useState(null);
    const [elapsed, setElapsed] = useState(0);
    const [lastChange, setLastChange] = useState(0);
    const [pollCount, setPollCount] = useState(0);
    const [stale, setStale] = useState(false);
    const intervalRef = useRef(null);
    const timerRef = useRef(null);
    const prevProgressRef = useRef(null);
    const startTimeRef = useRef(Date.now());

    useEffect(() => {
        const poll = async () => {
            try {
                const data = await api(`/video/veo3/status/${videoId}`);
                setStatus(data);
                setPollCount(c => c + 1);

                if (prevProgressRef.current !== null &&
                    (data.progress !== prevProgressRef.current || data.current_step !== prevProgressRef.currentStep)) {
                    setLastChange(0);
                    setStale(false);
                }
                prevProgressRef.current = data.progress;
                prevProgressRef.currentStep = data.current_step;

                if (data.status === 'completed' || data.status === 'failed') {
                    clearInterval(intervalRef.current);
                }
            } catch (err) {
                console.error('Poll error:', err);
            }
        };

        poll();
        intervalRef.current = setInterval(poll, 5000);

        timerRef.current = setInterval(() => {
            setElapsed(Math.floor((Date.now() - startTimeRef.current) / 1000));
            setLastChange(c => {
                const next = c + 1;
                if (next >= 120) setStale(true);
                return next;
            });
        }, 1000);

        return () => { clearInterval(intervalRef.current); clearInterval(timerRef.current); };
    }, [videoId]);

    if (!status) {
        return (
            <div className="text-center py-12">
                <svg className="animate-spin h-10 w-10 mx-auto text-indigo-600" viewBox="0 0 24 24">
                    <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none"/>
                    <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
                </svg>
                <p className="mt-3 text-gray-500">상태 확인 중...</p>
            </div>
        );
    }

    const isFailed = status.status === 'failed';
    const isDone = status.status === 'completed';
    const isRunning = !isFailed && !isDone;
    const currentOrder = STEP_LABELS[status.status]?.order ?? 0;

    const progressColor = isFailed ? 'bg-red-500' : isDone ? 'bg-green-500' : 'bg-indigo-600';

    return (
        <div className="fade-in max-w-xl mx-auto">
            {/* Header with elapsed time */}
            <div className="text-center mb-6">
                <h2 className="text-2xl font-bold text-gray-800">
                    {isDone ? '영상 생성 완료!' : isFailed ? '생성 실패' : '영상 생성 중...'}
                </h2>
                {isRunning && (
                    <div className="flex items-center justify-center gap-2 mt-2 text-sm text-gray-500">
                        <span className="inline-block w-2 h-2 rounded-full bg-green-500 animate-pulse"></span>
                        경과 시간: <span className="font-mono font-medium text-indigo-600">{formatElapsed(elapsed)}</span>
                    </div>
                )}
            </div>

            {/* Progress Bar */}
            <div className="mb-4">
                <div className="flex justify-between text-sm mb-2">
                    <span className="text-gray-700 font-medium">{status.current_step || '대기 중'}</span>
                    <span className="font-bold text-indigo-600">{status.progress}%</span>
                </div>
                <div className="w-full bg-gray-200 rounded-full h-3 overflow-hidden">
                    <div className={`progress-bar ${progressColor}`} style={{ width: `${Math.max(status.progress, isRunning ? 2 : 0)}%` }}>
                        {isRunning && <div style={{
                            width: '100%', height: '100%',
                            background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent)',
                            animation: 'shimmer 1.5s infinite',
                        }}></div>}
                    </div>
                </div>
            </div>

            {/* Step Timeline */}
            {isRunning && (
                <div className="bg-gray-50 rounded-lg p-4 mb-4">
                    <div className="space-y-2">
                        {Object.entries(STEP_LABELS).filter(([k]) => !['failed','completed'].includes(k)).map(([key, step]) => {
                            const isActive = status.status === key;
                            const isDoneStep = step.order < currentOrder;
                            return (
                                <div key={key} className={`flex items-center gap-3 text-sm py-1 px-2 rounded ${isActive ? 'bg-indigo-50 font-medium' : ''}`}>
                                    <span className="w-5 text-center">
                                        {isDoneStep ? '✅' : isActive ? step.icon : '○'}
                                    </span>
                                    <span className={isDoneStep ? 'text-gray-400 line-through' : isActive ? 'text-indigo-700' : 'text-gray-400'}>
                                        {step.label}
                                    </span>
                                    {isActive && (
                                        <span className="ml-auto text-xs text-indigo-500 animate-pulse">진행 중...</span>
                                    )}
                                </div>
                            );
                        })}
                    </div>
                </div>
            )}

            {/* Stale Warning */}
            {stale && isRunning && (
                <div className="bg-amber-50 border border-amber-300 rounded-lg p-3 mb-4 text-sm text-amber-700">
                    ⚠️ <span className="font-medium">{formatElapsed(lastChange)}</span> 동안 진행 상태가 변하지 않고 있습니다.
                    <span className="block mt-1 text-xs text-amber-600">
                        Veo 영상 생성은 클립당 5~10분 소요될 수 있습니다. 5분 이상 변화가 없으면 서버 로그를 확인해주세요.
                    </span>
                </div>
            )}

            {/* Error */}
            {isFailed && (
                <div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-4">
                    <div className="font-medium text-red-700 mb-1">오류 발생</div>
                    <p className="text-red-600 text-sm">{status.error_message || '알 수 없는 오류가 발생했습니다.'}</p>
                </div>
            )}

            {/* Footer info */}
            {isRunning && (
                <div className="text-center text-xs text-gray-400 space-y-1">
                    <div className="flex items-center justify-center gap-1">
                        <span className="inline-block w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse"></span>
                        5초마다 자동 확인 (폴링 #{pollCount})
                    </div>
                    {status.updated_at && (
                        <div>서버 마지막 업데이트: {new Date(status.updated_at).toLocaleTimeString('ko-KR')}</div>
                    )}
                </div>
            )}

            {/* Cost */}
            {status.cost_usd > 0 && (
                <div className="text-center text-sm text-gray-500 mt-3">
                    예상 비용: ${parseFloat(status.cost_usd).toFixed(4)}
                </div>
            )}
        </div>
    );
};

// ============================================================
// Step 5: Completed
// ============================================================
const CompletedView = ({ videoId }) => {
    return (
        <div className="fade-in max-w-lg mx-auto text-center">
            <div className="mb-6">
                <div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
                    <svg className="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
                    </svg>
                </div>
                <h2 className="text-2xl font-bold text-gray-800">YouTube Shorts 영상 완성!</h2>
                <p className="text-gray-500 mt-2">영상을 미리보기하고 다운로드하세요</p>
            </div>

            {/* Video Preview */}
            <div className="mb-6 bg-black rounded-lg overflow-hidden" style={{ maxHeight: '500px' }}>
                <video
                    src={`/video/veo3/preview/${videoId}`}
                    controls
                    className="w-full mx-auto"
                    style={{ maxHeight: '500px' }}
                />
            </div>

            <div className="flex gap-3 justify-center">
                <a
                    href={`/video/veo3/download/${videoId}`}
                    className="bg-indigo-600 text-white px-8 py-3 rounded-lg font-medium hover:bg-indigo-700 transition-colors inline-flex items-center gap-2"
                >
                    <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
                    </svg>
                    MP4 다운로드
                </a>
            </div>
        </div>
    );
};

// ============================================================
// History Table
// ============================================================
const HistoryTable = ({ onSelect, onDetail }) => {
    const [history, setHistory] = useState([]);
    const [loading, setLoading] = useState(true);
    const [checked, setChecked] = useState(new Set());
    const [deleting, setDeleting] = useState(false);
    const [refreshing, setRefreshing] = useState(false);

    const fetchHistory = (isRefresh = false) => {
        if (isRefresh) setRefreshing(true);
        api('/video/veo3/history')
            .then(data => { setHistory(data.data || []); setChecked(new Set()); })
            .catch(() => {})
            .finally(() => { setLoading(false); setRefreshing(false); });
    };

    useEffect(() => { fetchHistory(); }, []);

    const toggleCheck = (id) => {
        setChecked(prev => {
            const next = new Set(prev);
            next.has(id) ? next.delete(id) : next.add(id);
            return next;
        });
    };

    const toggleAll = () => {
        if (checked.size === history.length) {
            setChecked(new Set());
        } else {
            setChecked(new Set(history.map(h => h.id)));
        }
    };

    const handleDelete = async () => {
        if (checked.size === 0) return;
        if (!confirm(`선택한 ${checked.size}개 이력을 삭제하시겠습니까?`)) return;

        setDeleting(true);
        try {
            await api('/video/veo3/history', {
                method: 'DELETE',
                body: JSON.stringify({ ids: Array.from(checked) }),
            });
            fetchHistory();
        } catch (err) {
            alert('삭제 실패: ' + err.message);
        } finally {
            setDeleting(false);
        }
    };

    const formatKST = (dateStr) => {
        if (!dateStr) return '-';
        return new Date(dateStr).toLocaleString('ko-KR', {
            timeZone: 'Asia/Seoul',
            month: '2-digit', day: '2-digit',
            hour: '2-digit', minute: '2-digit',
            hour12: false,
        });
    };

    const formatDuration = (created, updated, status) => {
        if (!created || !updated) return '-';
        if (!['completed', 'failed'].includes(status)) return '진행 중';
        const diffSec = Math.floor((new Date(updated) - new Date(created)) / 1000);
        if (diffSec < 60) return `${diffSec}초`;
        const m = Math.floor(diffSec / 60);
        const s = diffSec % 60;
        return `${m}분 ${s}초`;
    };

    if (loading) return <div className="text-center py-4 text-gray-400">이력 로딩 중...</div>;
    if (history.length === 0) return null;

    const statusLabels = {
        pending: '대기',
        titles_generated: '제목 생성됨',
        scenario_ready: '시나리오 준비',
        generating_tts: 'TTS 생성',
        generating_clips: '영상 생성',
        generating_bgm: 'BGM 생성',
        assembling: '합성 중',
        completed: '완료',
        failed: '실패',
    };

    const statusColors = {
        completed: 'bg-green-100 text-green-700',
        failed: 'bg-red-100 text-red-700',
    };

    return (
        <div className="mt-12">
            <div className="flex items-center justify-between mb-4">
                <div className="flex items-center gap-2">
                    <h3 className="text-lg font-bold text-gray-700">생성 이력</h3>
                    <button
                        onClick={() => fetchHistory(true)}
                        disabled={refreshing}
                        className="p-1.5 text-gray-400 hover:text-indigo-600 hover:bg-indigo-50 rounded-lg transition-colors disabled:opacity-50"
                        title="새로고침"
                    >
                        <svg className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                        </svg>
                    </button>
                </div>
                {checked.size > 0 && (
                    <button
                        onClick={handleDelete}
                        disabled={deleting}
                        className="flex items-center gap-1.5 px-3 py-1.5 bg-red-500 text-white text-xs font-medium rounded-lg hover:bg-red-600 disabled:opacity-50 transition-colors"
                    >
                        <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                        </svg>
                        {deleting ? '삭제 중...' : `${checked.size}개 삭제`}
                    </button>
                )}
            </div>
            <div className="overflow-x-auto">
                <table className="w-full text-sm">
                    <thead>
                        <tr className="border-b bg-gray-50">
                            <th className="py-2 px-3 w-10">
                                <input
                                    type="checkbox"
                                    checked={history.length > 0 && checked.size === history.length}
                                    onChange={toggleAll}
                                    className="w-4 h-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 cursor-pointer"
                                />
                            </th>
                            <th className="text-left py-2 px-3 font-medium text-gray-500">생성일시</th>
                            <th className="text-left py-2 px-3 font-medium text-gray-500">제작시간</th>
                            <th className="text-left py-2 px-3 font-medium text-gray-500">키워드</th>
                            <th className="text-left py-2 px-3 font-medium text-gray-500">제목</th>
                            <th className="text-left py-2 px-3 font-medium text-gray-500">상태</th>
                            <th className="text-right py-2 px-3 font-medium text-gray-500">비용</th>
                            <th className="text-center py-2 px-3 font-medium text-gray-500">액션</th>
                        </tr>
                    </thead>
                    <tbody>
                        {history.map((item) => (
                            <tr
                                key={item.id}
                                className={`border-b hover:bg-gray-50 cursor-pointer ${checked.has(item.id) ? 'bg-indigo-50' : ''}`}
                                onClick={() => onDetail(item.id)}
                            >
                                <td className="py-2 px-3" onClick={e => e.stopPropagation()}>
                                    <input
                                        type="checkbox"
                                        checked={checked.has(item.id)}
                                        onChange={() => toggleCheck(item.id)}
                                        className="w-4 h-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 cursor-pointer"
                                    />
                                </td>
                                <td className="py-2 px-3 text-gray-600 whitespace-nowrap">{formatKST(item.created_at)}</td>
                                <td className="py-2 px-3 text-gray-600 whitespace-nowrap">{formatDuration(item.created_at, item.updated_at, item.status)}</td>
                                <td className="py-2 px-3 font-medium">{item.keyword}</td>
                                <td className="py-2 px-3 text-gray-600 truncate max-w-[200px]">{item.title || '-'}</td>
                                <td className="py-2 px-3">
                                    <span className={`px-2 py-0.5 rounded-full text-xs ${statusColors[item.status] || 'bg-blue-100 text-blue-700'}`}>
                                        {statusLabels[item.status] || item.status}
                                    </span>
                                </td>
                                <td className="py-2 px-3 text-right text-gray-600">
                                    {item.cost_usd > 0 ? `$${parseFloat(item.cost_usd).toFixed(2)}` : '-'}
                                </td>
                                <td className="py-2 px-3 text-center" onClick={e => e.stopPropagation()}>
                                    {item.status === 'completed' && (
                                        <a href={`/video/veo3/download/${item.id}`} className="text-indigo-600 hover:underline text-xs">
                                            다운로드
                                        </a>
                                    )}
                                    {['generating_tts','generating_clips','generating_bgm','assembling'].includes(item.status) && (
                                        <button onClick={() => onSelect(item.id)} className="text-blue-600 hover:underline text-xs">
                                            진행 확인
                                        </button>
                                    )}
                                    {!['completed','generating_tts','generating_clips','generating_bgm','assembling'].includes(item.status) && (
                                        <button onClick={() => onDetail(item.id)} className="text-gray-500 hover:underline text-xs">
                                            상세
                                        </button>
                                    )}
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </div>
    );
};

// ============================================================
// Detail Modal (이력 상세보기 + YouTube 텍스트)
// ============================================================
const DetailModal = ({ videoId, onClose }) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState('');
    const [copiedField, setCopiedField] = useState('');
    const [activeTab, setActiveTab] = useState('scenario');

    useEffect(() => {
        if (!videoId) return;
        setLoading(true);
        setError('');
        api(`/video/veo3/detail/${videoId}`)
            .then(res => setData(res.data))
            .catch(err => setError(err.message))
            .finally(() => setLoading(false));
    }, [videoId]);

    const copyToClipboard = (text, field) => {
        navigator.clipboard.writeText(text).then(() => {
            setCopiedField(field);
            setTimeout(() => setCopiedField(''), 2000);
        });
    };

    const statusLabels = {
        pending: '대기', titles_generated: '제목 생성됨', scenario_ready: '시나리오 준비',
        generating_tts: 'TTS 생성', generating_clips: '영상 생성', generating_bgm: 'BGM 생성',
        assembling: '합성 중', completed: '완료', failed: '실패',
    };

    if (!videoId) return null;

    return (
        <div className="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4" onClick={onClose}>
            <div className="bg-white rounded-xl shadow-2xl max-w-3xl w-full max-h-[90vh] overflow-hidden flex flex-col" onClick={e => e.stopPropagation()}>
                {/* Header */}
                <div className="flex items-center justify-between px-6 py-4 border-b bg-gray-50">
                    <h3 className="text-lg font-bold text-gray-800">생성 상세 정보</h3>
                    <button onClick={onClose} className="text-gray-400 hover:text-gray-600 text-xl leading-none">&times;</button>
                </div>

                {/* Content */}
                <div className="flex-1 overflow-y-auto p-6">
                    {loading && (
                        <div className="text-center py-12">
                            <svg className="animate-spin h-8 w-8 mx-auto text-indigo-600" viewBox="0 0 24 24"><circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none"/><path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/></svg>
                            <p className="mt-3 text-gray-500 text-sm">데이터 로딩 중...</p>
                        </div>
                    )}

                    {error && (
                        <div className="bg-red-50 border border-red-200 rounded-lg p-4 text-red-700 text-sm">{error}</div>
                    )}

                    {data && !loading && (
                        <>
                            {/* Summary */}
                            <div className="grid grid-cols-2 gap-4 mb-6">
                                <div className="bg-gray-50 rounded-lg p-3">
                                    <div className="text-xs text-gray-500 mb-1">키워드</div>
                                    <div className="font-medium text-gray-800">{data.keyword}</div>
                                </div>
                                <div className="bg-gray-50 rounded-lg p-3">
                                    <div className="text-xs text-gray-500 mb-1">상태</div>
                                    <div className="font-medium">{statusLabels[data.status] || data.status}</div>
                                </div>
                                <div className="bg-gray-50 rounded-lg p-3">
                                    <div className="text-xs text-gray-500 mb-1">비용</div>
                                    <div className="font-medium text-gray-800">{data.cost_usd > 0 ? `$${parseFloat(data.cost_usd).toFixed(2)}` : '-'}</div>
                                </div>
                                <div className="bg-gray-50 rounded-lg p-3">
                                    <div className="text-xs text-gray-500 mb-1">생성일시</div>
                                    <div className="font-medium text-gray-800 text-sm">{data.created_at ? new Date(data.created_at).toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' }) : '-'}</div>
                                </div>
                            </div>

                            {/* Title */}
                            <div className="mb-6 bg-indigo-50 border border-indigo-200 rounded-lg p-4">
                                <div className="text-xs text-indigo-600 font-medium mb-1">제목</div>
                                <div className="text-lg font-bold text-gray-800">{data.title || '-'}</div>
                            </div>

                            {/* Error (if failed) */}
                            {data.status === 'failed' && data.error_message && (
                                <div className="mb-6 bg-red-50 border border-red-200 rounded-lg p-4">
                                    <div className="text-xs text-red-600 font-medium mb-1">에러 메시지</div>
                                    <div className="text-sm text-red-700">{data.error_message}</div>
                                </div>
                            )}

                            {/* Tabs */}
                            <div className="border-b mb-4">
                                <div className="flex gap-1">
                                    {[
                                        { id: 'scenario', label: '시나리오/프롬프트' },
                                        ...(data.youtube_text ? [{ id: 'youtube', label: 'YouTube 텍스트' }] : []),
                                    ].map(tab => (
                                        <button
                                            key={tab.id}
                                            onClick={() => setActiveTab(tab.id)}
                                            className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
                                                activeTab === tab.id
                                                    ? 'border-indigo-600 text-indigo-600'
                                                    : 'border-transparent text-gray-500 hover:text-gray-700'
                                            }`}
                                        >
                                            {tab.label}
                                        </button>
                                    ))}
                                </div>
                            </div>

                            {/* Tab: Scenario */}
                            {activeTab === 'scenario' && data.scenes && data.scenes.length > 0 && (
                                <div className="space-y-4">
                                    {/* BGM Mood */}
                                    {data.scenario?.bgm_mood && (
                                        <div className="flex items-center gap-2 text-sm text-gray-600 mb-2">
                                            <span className="px-2 py-0.5 bg-purple-100 text-purple-700 rounded-full text-xs font-medium">BGM</span>
                                            {data.scenario.bgm_mood}
                                        </div>
                                    )}

                                    {data.scenes.map((scene, i) => (
                                        <div key={i} className="border border-gray-200 rounded-lg overflow-hidden">
                                            <div className="bg-gray-50 px-4 py-2 flex items-center justify-between">
                                                <span className="text-sm font-bold text-indigo-600">
                                                    #{scene.scene_number} {scene.scene_type || ''} ({scene.duration}s)
                                                </span>
                                                <span className="text-xs text-gray-500">{scene.mood}</span>
                                            </div>
                                            <div className="p-4 space-y-3">
                                                <div>
                                                    <div className="text-xs text-gray-500 font-medium mb-1">나레이션</div>
                                                    <div className="text-sm text-gray-800 bg-yellow-50 p-2 rounded">{scene.narration || '(없음)'}</div>
                                                </div>
                                                <div>
                                                    <div className="text-xs text-gray-500 font-medium mb-1">Visual Prompt</div>
                                                    <div className="text-xs text-gray-700 bg-blue-50 p-2 rounded font-mono whitespace-pre-wrap">{scene.visual_prompt || '(없음)'}</div>
                                                </div>
                                            </div>
                                        </div>
                                    ))}
                                </div>
                            )}

                            {activeTab === 'scenario' && (!data.scenes || data.scenes.length === 0) && (
                                <div className="text-center py-8 text-gray-400 text-sm">시나리오 데이터가 없습니다</div>
                            )}

                            {/* Tab: YouTube Text */}
                            {activeTab === 'youtube' && data.youtube_text && (
                                <div className="space-y-6">
                                    {/* YouTube Title */}
                                    <div>
                                        <div className="flex items-center justify-between mb-2">
                                            <label className="text-sm font-bold text-gray-700">Shorts 제목</label>
                                            <button
                                                onClick={() => copyToClipboard(data.youtube_text.title, 'title')}
                                                className={`text-xs px-3 py-1 rounded-full font-medium transition-all ${
                                                    copiedField === 'title'
                                                        ? 'bg-green-100 text-green-700'
                                                        : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
                                                }`}
                                            >
                                                {copiedField === 'title' ? '복사됨!' : '복사'}
                                            </button>
                                        </div>
                                        <div className="bg-gray-50 border border-gray-200 rounded-lg p-3 text-sm text-gray-800 font-medium">
                                            {data.youtube_text.title}
                                        </div>
                                    </div>

                                    {/* YouTube Description */}
                                    <div>
                                        <div className="flex items-center justify-between mb-2">
                                            <label className="text-sm font-bold text-gray-700">Shorts 설명란</label>
                                            <button
                                                onClick={() => copyToClipboard(data.youtube_text.description, 'desc')}
                                                className={`text-xs px-3 py-1 rounded-full font-medium transition-all ${
                                                    copiedField === 'desc'
                                                        ? 'bg-green-100 text-green-700'
                                                        : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
                                                }`}
                                            >
                                                {copiedField === 'desc' ? '복사됨!' : '복사'}
                                            </button>
                                        </div>
                                        <pre className="bg-gray-50 border border-gray-200 rounded-lg p-3 text-sm text-gray-800 whitespace-pre-wrap font-sans">
                                            {data.youtube_text.description}
                                        </pre>
                                    </div>

                                    {/* Hashtags */}
                                    <div>
                                        <div className="flex items-center justify-between mb-2">
                                            <label className="text-sm font-bold text-gray-700">해시태그</label>
                                            <button
                                                onClick={() => copyToClipboard(data.youtube_text.hashtags.join(' '), 'tags')}
                                                className={`text-xs px-3 py-1 rounded-full font-medium transition-all ${
                                                    copiedField === 'tags'
                                                        ? 'bg-green-100 text-green-700'
                                                        : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
                                                }`}
                                            >
                                                {copiedField === 'tags' ? '복사됨!' : '복사'}
                                            </button>
                                        </div>
                                        <div className="flex flex-wrap gap-2">
                                            {data.youtube_text.hashtags.map((tag, i) => (
                                                <span key={i} className="px-2 py-1 bg-blue-50 text-blue-700 rounded-full text-xs font-medium">{tag}</span>
                                            ))}
                                        </div>
                                    </div>
                                </div>
                            )}
                        </>
                    )}
                </div>

                {/* Footer */}
                {data && data.status === 'completed' && (
                    <div className="flex items-center justify-between px-6 py-3 border-t bg-gray-50">
                        <a
                            href={`/video/veo3/preview/${data.id}`}
                            target="_blank"
                            className="text-sm text-indigo-600 hover:text-indigo-800 font-medium"
                        >
                            미리보기
                        </a>
                        <a
                            href={`/video/veo3/download/${data.id}`}
                            className="inline-flex items-center gap-1.5 px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-lg hover:bg-indigo-700 transition-colors"
                        >
                            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
                            </svg>
                            다운로드
                        </a>
                    </div>
                )}
            </div>
        </div>
    );
};

// ============================================================
// Main App
// ============================================================
const App = () => {
    const [step, setStep] = useState(1);
    const [loading, setLoading] = useState(false);
    const [videoId, setVideoId] = useState(null);
    const [titles, setTitles] = useState([]);
    const [scenario, setScenario] = useState(null);
    const [keyword, setKeyword] = useState('');
    const [error, setError] = useState('');
    const [detailId, setDetailId] = useState(null);

    // Step 1: Generate Titles
    const handleKeywordSubmit = async (kw, trendingContext = null) => {
        setLoading(true);
        setError('');
        setKeyword(kw);
        try {
            const body = { keyword: kw };
            if (trendingContext) body.trending_context = trendingContext;
            const data = await api('/video/veo3/titles', {
                method: 'POST',
                body: JSON.stringify(body),
            });
            setVideoId(data.video_id);
            setTitles(data.titles);
            setStep(2);
        } catch (err) {
            setError(err.message);
        } finally {
            setLoading(false);
        }
    };

    // Step 2: Select Title → Generate Scenario
    const handleTitleSelect = async (title) => {
        setLoading(true);
        setError('');
        try {
            const data = await api('/video/veo3/scenario', {
                method: 'POST',
                body: JSON.stringify({ video_id: videoId, title }),
            });
            setScenario(data.scenario);
            setStep(3);
        } catch (err) {
            setError(err.message);
        } finally {
            setLoading(false);
        }
    };

    // Step 3: Start Generation
    const handleGenerate = async (editedScenario) => {
        setLoading(true);
        setError('');
        try {
            await api('/video/veo3/generate', {
                method: 'POST',
                body: JSON.stringify({ video_id: videoId, scenario: editedScenario }),
            });
            setStep(4);
        } catch (err) {
            setError(err.message);
        } finally {
            setLoading(false);
        }
    };

    // History item click → jump to progress
    const handleHistorySelect = (id) => {
        setVideoId(id);
        setStep(4);
    };

    // Determine actual display step from polling status
    const ProgressWithCompletion = ({ videoId }) => {
        const [done, setDone] = useState(false);
        const [failed, setFailed] = useState(false);

        useEffect(() => {
            const check = async () => {
                try {
                    const data = await api(`/video/veo3/status/${videoId}`);
                    if (data.status === 'completed') setDone(true);
                    if (data.status === 'failed') setFailed(true);
                } catch (err) {}
            };
            check();
            const iv = setInterval(check, 5000);
            return () => clearInterval(iv);
        }, [videoId]);

        if (done) return <CompletedView videoId={videoId} />;
        return <GenerationProgress videoId={videoId} />;
    };

    return (
        <div className="max-w-4xl mx-auto">
            {/* Header */}
            <div className="text-center mb-8">
                <h1 className="text-3xl font-bold text-gray-900">YouTube Shorts AI 생성기</h1>
                <p className="text-gray-500 mt-2">키워드 하나로 AI가 YouTube Shorts 영상을 자동 생성합니다</p>
                <p className="text-xs text-gray-400 mt-1">Gemini 3.0 Flash + Veo 3.1 + Google TTS</p>
            </div>

            {/* Step Indicator */}
            <StepIndicator currentStep={step} />

            {/* Error */}
            {error && (
                <div className="max-w-lg mx-auto mb-6 bg-red-50 border border-red-200 rounded-lg p-3 text-red-700 text-sm">
                    {error}
                    <button onClick={() => setError('')} className="ml-2 text-red-500 hover:text-red-700">✕</button>
                </div>
            )}

            {/* Steps */}
            {step === 1 && <KeywordInput onSubmit={handleKeywordSubmit} loading={loading} />}
            {step === 2 && <TitleSelection titles={titles} onSelect={handleTitleSelect} onBack={() => setStep(1)} loading={loading} />}
            {step === 3 && scenario && <ScenarioPreview scenario={scenario} onGenerate={handleGenerate} onBack={() => setStep(2)} loading={loading} />}
            {step >= 4 && videoId && <ProgressWithCompletion videoId={videoId} />}

            {/* New Generation Button (after completion) */}
            {step >= 4 && (
                <div className="text-center mt-8">
                    <button
                        onClick={() => { setStep(1); setVideoId(null); setTitles([]); setScenario(null); setError(''); }}
                        className="text-indigo-600 hover:text-indigo-800 text-sm font-medium"
                    >
                        + 새 영상 만들기
                    </button>
                </div>
            )}

            {/* History */}
            <HistoryTable onSelect={handleHistorySelect} onDetail={(id) => setDetailId(id)} />

            {/* Detail Modal */}
            {detailId && <DetailModal videoId={detailId} onClose={() => setDetailId(null)} />}
        </div>
    );
};

ReactDOM.createRoot(document.getElementById('veo3-root')).render(<App />);
</script>
@endverbatim
@endpush
