#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
YouTube 동영상을 1분 쇼츠로 자동 변환하는 프로그램 (수정 버전)
Author: 최만규
"""

import os
import sys
import argparse
from pathlib import Path
from datetime import datetime
import yt_dlp
from moviepy.editor import VideoFileClip, CompositeVideoClip, TextClip
from moviepy.video.fx.all import resize, speedx

# ALSA 경고 메시지 숨기기
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "1"
os.environ['SDL_AUDIODRIVER'] = 'dummy'


class YouTubeShortsConverter:
    """유튜브 동영상을 1분 쇼츠로 변환하는 클래스"""
    
    def __init__(self, output_dir="./shorts_output"):
        """
        초기화
        
        Args:
            output_dir (str): 출력 디렉토리 경로
        """
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(exist_ok=True)
        self.temp_dir = self.output_dir / "temp"
        self.temp_dir.mkdir(exist_ok=True)
        
    def download_youtube_video(self, url):
        """
        유튜브 동영상 다운로드 (개선된 버전)
        
        Args:
            url (str): 유튜브 URL
            
        Returns:
            tuple: (다운로드된 파일 경로, 동영상 제목)
        """
        print(f"📥 유튜브 동영상 다운로드 중: {url}")
        
        # 다운로드 옵션 설정 (개선됨)
        ydl_opts = {
            # 포맷 선택을 매우 유연하게 (여러 대체 옵션)
            'format': (
                'bestvideo[ext=mp4][height<=1080]+bestaudio[ext=m4a]/best[ext=mp4][height<=1080]/'
                'bestvideo[ext=mp4]+bestaudio/best[ext=mp4]/'
                'bestvideo+bestaudio/best'
            ),
            'outtmpl': str(self.temp_dir / '%(id)s.%(ext)s'),
            'quiet': False,
            'no_warnings': False,
            
            # 병합 설정
            'merge_output_format': 'mp4',
            'postprocessors': [{
                'key': 'FFmpegVideoConvertor',
                'preferedformat': 'mp4',
            }],
            
            # 에러 처리
            'ignoreerrors': False,
            'no_abort_on_error': False,
            
            # 유튜브 제한 우회 옵션
            'nocheckcertificate': True,
            'prefer_insecure': False,
            
            # 사용자 에이전트 설정 (브라우저처럼 보이도록)
            'http_headers': {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language': 'en-us,en;q=0.5',
                'Sec-Fetch-Mode': 'navigate',
            },
            
            # 속도 제한 우회
            'extractor_args': {
                'youtube': {
                    'player_client': ['android', 'web'],
                    'skip': ['hls', 'dash']
                }
            },
        }
        
        try:
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                print("🔍 동영상 정보 추출 중...")
                info = ydl.extract_info(url, download=False)
                
                # 사용 가능한 포맷 확인
                if 'formats' in info:
                    print(f"📊 사용 가능한 포맷: {len(info['formats'])}개")
                
                # 다운로드 시작
                print("⬇️  다운로드 시작...")
                info = ydl.extract_info(url, download=True)
                
                video_id = info['id']
                video_title = info['title']
                
                # 다운로드된 파일 찾기
                possible_extensions = ['mp4', 'webm', 'mkv', 'avi']
                downloaded_file = None
                
                for ext in possible_extensions:
                    candidate = self.temp_dir / f"{video_id}.{ext}"
                    if candidate.exists():
                        downloaded_file = candidate
                        break
                
                if not downloaded_file:
                    # 디렉토리에서 가장 최근 파일 찾기
                    files = list(self.temp_dir.glob("*"))
                    if files:
                        downloaded_file = max(files, key=lambda x: x.stat().st_mtime)
                
                if not downloaded_file or not downloaded_file.exists():
                    raise Exception("다운로드된 파일을 찾을 수 없습니다.")
                
                print(f"✅ 다운로드 완료: {video_title}")
                print(f"📁 파일 위치: {downloaded_file}")
                print(f"📦 파일 크기: {downloaded_file.stat().st_size / (1024*1024):.2f} MB")
                
                return str(downloaded_file), video_title
                
        except yt_dlp.utils.DownloadError as e:
            error_msg = str(e)
            print(f"\n❌ 다운로드 오류 발생!")
            print(f"오류 내용: {error_msg}")
            
            # 구체적인 해결 방법 제시
            if "Requested format is not available" in error_msg:
                print("\n💡 해결 방법:")
                print("1. yt-dlp 업데이트: pip install --upgrade yt-dlp")
                print("2. 다른 동영상으로 시도해보세요")
                print("3. 동영상이 제한되어 있을 수 있습니다 (연령 제한, 지역 제한 등)")
                
            elif "nsig extraction failed" in error_msg:
                print("\n💡 해결 방법:")
                print("yt-dlp를 최신 버전으로 업데이트하세요:")
                print("pip install --upgrade yt-dlp")
                
            raise
            
        except Exception as e:
            print(f"❌ 다운로드 실패: {str(e)}")
            raise
    
    def create_shorts_video(self, video_path, target_duration=60, add_watermark=False):
        """
        1분 쇼츠 동영상 생성 (속도 조정 방식)
        
        Args:
            video_path (str): 원본 동영상 경로
            target_duration (int): 목표 길이 (초)
            add_watermark (bool): 워터마크 추가 여부
            
        Returns:
            str: 생성된 쇼츠 동영상 경로
        """
        print(f"\n🎬 쇼츠 동영상 생성 중...")
        
        try:
            # 원본 동영상 로드
            video = VideoFileClip(video_path)
            original_duration = video.duration
            
            print(f"⏱️  원본 길이: {original_duration:.1f}초 ({original_duration/60:.1f}분)")
            print(f"🎯 목표 길이: {target_duration}초")
            
            # 속도 배율 계산
            speed_factor = original_duration / target_duration
            print(f"⚡ 재생 속도: {speed_factor:.2f}x")
            
            # 속도 조정
            fast_video = video.speedx(speed_factor)
            
            # 쇼츠 포맷 (9:16 세로 비율)로 변환
            original_width, original_height = video.size
            original_ratio = original_width / original_height
            
            # 세로 동영상 크기 (1080x1920 - 쇼츠 표준)
            shorts_width = 1080
            shorts_height = 1920
            
            print(f"📐 원본 해상도: {original_width}x{original_height}")
            print(f"📐 쇼츠 해상도: {shorts_width}x{shorts_height}")
            
            # 비율에 맞게 리사이즈
            if original_ratio > (shorts_width / shorts_height):
                # 가로가 더 긴 경우 - 높이 기준으로 맞춤
                resized_video = fast_video.resize(height=shorts_height)
            else:
                # 세로가 더 긴 경우 - 너비 기준으로 맞춤
                resized_video = fast_video.resize(width=shorts_width)
            
            # 중앙 크롭
            resized_width, resized_height = resized_video.size
            x_center = resized_width / 2
            y_center = resized_height / 2
            
            final_video = resized_video.crop(
                x_center=x_center,
                y_center=y_center,
                width=shorts_width,
                height=shorts_height
            )
            
            # 워터마크 추가 (옵션)
            if add_watermark:
                try:
                    watermark = TextClip(
                        "Made by YouTube Shorts Maker",
                        fontsize=30,
                        color='white',
                        font='Arial',
                        stroke_color='black',
                        stroke_width=2
                    ).set_position(('center', 0.95), relative=True).set_duration(final_video.duration)
                    
                    final_video = CompositeVideoClip([final_video, watermark])
                except Exception as e:
                    print(f"⚠️  워터마크 추가 실패 (계속 진행): {str(e)}")
            
            # 출력 파일명 생성
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            output_filename = f"shorts_{timestamp}.mp4"
            output_path = self.output_dir / output_filename
            
            print(f"\n💾 동영상 인코딩 중...")
            print(f"   출력: {output_path}")
            
            # 동영상 저장
            final_video.write_videofile(
                str(output_path),
                codec='libx264',
                audio_codec='aac',
                fps=30,
                preset='medium',
                bitrate='5000k',
                audio=True,
                verbose=False,
                logger=None
            )
            
            # 리소스 정리
            video.close()
            fast_video.close()
            resized_video.close()
            final_video.close()
            
            print(f"\n✅ 쇼츠 동영상 생성 완료!")
            print(f"📁 저장 위치: {output_path}")
            
            # 원본 크기와 생성된 크기 비교
            original_size = os.path.getsize(video_path) / (1024 * 1024)
            output_size = os.path.getsize(output_path) / (1024 * 1024)
            print(f"📊 원본 크기: {original_size:.2f} MB")
            print(f"📊 쇼츠 크기: {output_size:.2f} MB")
            print(f"📊 압축률: {(1 - output_size/original_size) * 100:.1f}%")
            
            return str(output_path)
            
        except Exception as e:
            print(f"❌ 쇼츠 생성 실패: {str(e)}")
            raise
    
    def cleanup_temp_files(self):
        """임시 파일 정리"""
        print(f"\n🧹 임시 파일 정리 중...")
        try:
            for file in self.temp_dir.glob("*"):
                file.unlink()
                print(f"  삭제: {file.name}")
        except Exception as e:
            print(f"⚠️  임시 파일 정리 중 오류: {str(e)}")
    
    def convert_url_to_shorts(self, youtube_url, target_duration=60, 
                             add_watermark=False, keep_temp=False):
        """
        유튜브 URL을 받아서 쇼츠로 변환 (전체 프로세스)
        
        Args:
            youtube_url (str): 유튜브 URL
            target_duration (int): 목표 길이 (초)
            add_watermark (bool): 워터마크 추가 여부
            keep_temp (bool): 임시 파일 유지 여부
            
        Returns:
            str: 생성된 쇼츠 동영상 경로
        """
        print("=" * 60)
        print("🎥 YouTube Shorts Maker 시작")
        print("=" * 60)
        
        try:
            # 1. 유튜브 동영상 다운로드
            video_path, video_title = self.download_youtube_video(youtube_url)
            
            # 2. 쇼츠 동영상 생성
            shorts_path = self.create_shorts_video(
                video_path,
                target_duration=target_duration,
                add_watermark=add_watermark
            )
            
            # 3. 임시 파일 정리
            if not keep_temp:
                self.cleanup_temp_files()
            
            print("\n" + "=" * 60)
            print("🎉 모든 작업 완료!")
            print("=" * 60)
            
            return shorts_path
            
        except Exception as e:
            print(f"\n❌ 작업 실패: {str(e)}")
            raise


def main():
    """메인 함수"""
    parser = argparse.ArgumentParser(
        description='유튜브 동영상을 1분 쇼츠로 변환합니다.',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
사용 예시:
  python youtube_shorts_maker.py "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  python youtube_shorts_maker.py "https://youtu.be/dQw4w9WgXcQ" -d 30
  python youtube_shorts_maker.py "URL" -w --keep-temp
  
문제 해결:
  다운로드 오류 시: pip install --upgrade yt-dlp
        """
    )
    
    parser.add_argument(
        'url',
        help='유튜브 동영상 URL'
    )
    
    parser.add_argument(
        '-d', '--duration',
        type=int,
        default=60,
        help='목표 동영상 길이 (초) (기본값: 60)'
    )
    
    parser.add_argument(
        '-o', '--output',
        default='./shorts_output',
        help='출력 디렉토리 (기본값: ./shorts_output)'
    )
    
    parser.add_argument(
        '-w', '--watermark',
        action='store_true',
        help='워터마크 추가'
    )
    
    parser.add_argument(
        '--keep-temp',
        action='store_true',
        help='임시 파일 유지'
    )
    
    args = parser.parse_args()
    
    # 변환 실행
    converter = YouTubeShortsConverter(output_dir=args.output)
    
    try:
        shorts_path = converter.convert_url_to_shorts(
            youtube_url=args.url,
            target_duration=args.duration,
            add_watermark=args.watermark,
            keep_temp=args.keep_temp
        )
        
        print(f"\n✨ 생성된 쇼츠: {shorts_path}")
        
    except Exception as e:
        print(f"\n💥 오류 발생: {str(e)}")
        print("\n💡 문제 해결:")
        print("1. yt-dlp 업데이트: pip install --upgrade yt-dlp")
        print("2. FFmpeg 설치 확인: ffmpeg -version")
        print("3. 다른 동영상으로 테스트")
        sys.exit(1)


if __name__ == "__main__":
    main()