import sys
import os
import subprocess
import json
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                             QHBoxLayout, QPushButton, QListWidget, QSlider, 
                             QLabel, QFileDialog, QSplitter, QFrame, QComboBox)
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import Qt, QUrl, QTimer
from PyQt5.QtGui import QIcon, QFont

class VideoPlayer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Yeson 비디오 플레이어")
        self.setGeometry(100, 100, 1200, 800)
        
        # 미디어 플레이어 초기화
        self.media_player = QMediaPlayer()
        self.video_widget = QVideoWidget()
        self.media_player.setVideoOutput(self.video_widget)
        
        # 현재 재생 중인 파일 인덱스
        self.current_file_index = 0
        self.video_files = []
        
        # 프레임 관련 변수
        self.fps = 0
        self.total_frames = 0
        
        # UI 초기화
        self.init_ui()
        self.setup_connections()
        
        # 타이머 설정 (재생 시간 업데이트용)
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.update_time)
        
    def init_ui(self):
        # 중앙 위젯 설정
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 메인 레이아웃 (수평 분할)
        main_layout = QHBoxLayout(central_widget)
        
        # 사이드바 (파일 목록)
        self.create_sidebar()
        
        # 메인 콘텐츠 영역
        content_widget = QWidget()
        content_layout = QVBoxLayout(content_widget)
        
        # 비디오 재생 영역
        self.video_widget.setMinimumSize(640, 480)
        content_layout.addWidget(self.video_widget)
        
        # 컨트롤 영역
        self.create_controls(content_layout)
        
        # 분할기로 사이드바와 메인 콘텐츠 분리
        splitter = QSplitter(Qt.Horizontal)
        splitter.addWidget(self.sidebar_widget)
        splitter.addWidget(content_widget)
        splitter.setSizes([300, 900])  # 사이드바 300px, 메인 콘텐츠 900px
        
        main_layout.addWidget(splitter)
        
    def create_sidebar(self):
        self.sidebar_widget = QWidget()
        sidebar_layout = QVBoxLayout(self.sidebar_widget)
        
        # 사이드바 제목
        title_label = QLabel("파일 목록")
        title_label.setFont(QFont("Arial", 14, QFont.Bold))
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("background-color: #2c3e50; color: white; padding: 10px;")
        sidebar_layout.addWidget(title_label)
        
        # 파일 목록 위젯
        self.file_list = QListWidget()
        self.file_list.setStyleSheet("""
            QListWidget {
                background-color: #34495e;
                color: white;
                border: none;
                font-size: 12px;
            }
            QListWidget::item {
                padding: 8px;
                border-bottom: 1px solid #2c3e50;
            }
            QListWidget::item:selected {
                background-color: #3498db;
            }
            QListWidget::item:hover {
                background-color: #2980b9;
            }
        """)
        sidebar_layout.addWidget(self.file_list)
        
        # 파일 추가 버튼
        add_file_btn = QPushButton("파일 추가")
        add_file_btn.setStyleSheet("""
            QPushButton {
                background-color: #27ae60;
                color: white;
                border: none;
                padding: 10px;
                font-size: 12px;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #229954;
            }
        """)
        add_file_btn.clicked.connect(self.add_files)
        sidebar_layout.addWidget(add_file_btn)
        
        # 폴더 추가 버튼
        add_folder_btn = QPushButton("폴더 추가")
        add_folder_btn.setStyleSheet("""
            QPushButton {
                background-color: #e67e22;
                color: white;
                border: none;
                padding: 10px;
                font-size: 12px;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #d35400;
            }
        """)
        add_folder_btn.clicked.connect(self.add_folder)
        sidebar_layout.addWidget(add_folder_btn)
        
    def create_controls(self, layout):
        # 컨트롤 프레임
        control_frame = QFrame()
        control_frame.setStyleSheet("""
            QFrame {
                background-color: #2c3e50;
                border-radius: 5px;
                margin: 5px;
            }
        """)
        control_layout = QVBoxLayout(control_frame)
        
        # 재생 시간 표시
        time_layout = QHBoxLayout()
        
        # 정보 선택 콤보 박스
        info_selection_layout = QHBoxLayout()
        info_selection_layout.addWidget(QLabel("표시 정보:"))
        
        self.info_combo = QComboBox()
        self.info_combo.addItems(["시간 + 프레임", "시간만", "프레임만"])
        self.info_combo.setCurrentText("시간 + 프레임")
        self.info_combo.setStyleSheet("""
            QComboBox {
                background-color: #34495e;
                color: white;
                border: 1px solid #7f8c8d;
                border-radius: 3px;
                padding: 5px;
                font-size: 11px;
            }
            QComboBox::drop-down {
                border: none;
                width: 20px;
            }
            QComboBox::down-arrow {
                image: none;
                border-left: 5px solid transparent;
                border-right: 5px solid transparent;
                border-top: 5px solid white;
            }
            QComboBox QAbstractItemView {
                background-color: #34495e;
                color: white;
                selection-background-color: #3498db;
            }
        """)
        self.info_combo.currentTextChanged.connect(self.update_info_display)
        info_selection_layout.addWidget(self.info_combo)
        info_selection_layout.addStretch()
        
        time_layout.addLayout(info_selection_layout)
        time_layout.addStretch()
        
        # FPS 정보 (오른쪽)
        self.fps_label = QLabel("FPS: 0")
        self.fps_label.setStyleSheet("color: #e74c3c; font-size: 12px; font-weight: bold;")
        time_layout.addWidget(self.fps_label)
        
        control_layout.addLayout(time_layout)
        
        # 정보 표시 영역
        self.info_display_layout = QVBoxLayout()
        
        # 시간 정보 (왼쪽)
        self.time_info_layout = QVBoxLayout()
        
        # 현재 시간과 총 시간
        current_total_layout = QHBoxLayout()
        self.current_time_label = QLabel("00:00")
        self.total_time_label = QLabel("00:00")
        self.current_time_label.setStyleSheet("color: white; font-size: 12px; font-weight: bold;")
        self.total_time_label.setStyleSheet("color: white; font-size: 12px; font-weight: bold;")
        
        current_total_layout.addWidget(QLabel("시간:"))
        current_total_layout.addWidget(self.current_time_label)
        current_total_layout.addWidget(QLabel("/"))
        current_total_layout.addWidget(self.total_time_label)
        current_total_layout.addStretch()
        
        self.time_info_layout.addLayout(current_total_layout)
        
        # 프레임 정보
        self.frame_info_layout = QHBoxLayout()
        self.current_frame_label = QLabel("0")
        self.total_frames_label = QLabel("0")
        self.current_frame_label.setStyleSheet("color: #3498db; font-size: 12px; font-weight: bold;")
        self.total_frames_label.setStyleSheet("color: #3498db; font-size: 12px; font-weight: bold;")
        
        self.frame_info_layout.addWidget(QLabel("프레임:"))
        self.frame_info_layout.addWidget(self.current_frame_label)
        self.frame_info_layout.addWidget(QLabel("/"))
        self.frame_info_layout.addWidget(self.total_frames_label)
        self.frame_info_layout.addStretch()
        
        self.time_info_layout.addLayout(self.frame_info_layout)
        
        # 정보 표시 위젯들
        self.time_info_widget = QWidget()
        self.time_info_widget.setLayout(self.time_info_layout)
        
        # 프레임 전용 위젯 (시간 정보 없이)
        self.frame_only_widget = QWidget()
        frame_only_layout = QHBoxLayout(self.frame_only_widget)
        frame_only_layout.addWidget(QLabel("프레임:"))
        frame_only_layout.addWidget(self.current_frame_label)
        frame_only_layout.addWidget(QLabel("/"))
        frame_only_layout.addWidget(self.total_frames_label)
        frame_only_layout.addStretch()
        
        self.frame_info_widget = QWidget()
        self.frame_info_widget.setLayout(self.frame_info_layout)
        
        # 초기 표시 설정
        self.info_display_layout.addWidget(self.time_info_widget)
        self.info_display_layout.addWidget(self.frame_info_widget)
        
        control_layout.addLayout(self.info_display_layout)
        
        # 재생 진행 슬라이더
        self.progress_slider = QSlider(Qt.Horizontal)
        self.progress_slider.setStyleSheet("""
            QSlider::groove:horizontal {
                border: 1px solid #bdc3c7;
                height: 8px;
                background: #34495e;
                border-radius: 4px;
            }
            QSlider::handle:horizontal {
                background: #3498db;
                border: 1px solid #2980b9;
                width: 18px;
                margin: -2px 0;
                border-radius: 9px;
            }
            QSlider::sub-page:horizontal {
                background: #3498db;
                border-radius: 4px;
            }
        """)
        control_layout.addWidget(self.progress_slider)
        
        # 컨트롤 버튼들
        button_layout = QHBoxLayout()
        
        # 이전 버튼
        self.prev_button = QPushButton("⏮")
        self.prev_button.setToolTip("이전 파일")
        self.prev_button.setFixedSize(50, 40)
        
        # 재생/정지 버튼
        self.play_button = QPushButton("▶")
        self.play_button.setToolTip("재생/정지")
        self.play_button.setFixedSize(60, 40)
        
        # 다음 버튼
        self.next_button = QPushButton("⏭")
        self.next_button.setToolTip("다음 파일")
        self.next_button.setFixedSize(50, 40)
        
        # 볼륨 슬라이더
        self.volume_slider = QSlider(Qt.Horizontal)
        self.volume_slider.setRange(0, 100)
        self.volume_slider.setValue(50)
        self.volume_slider.setFixedWidth(100)
        self.volume_slider.setToolTip("볼륨")
        
        # 버튼 스타일 적용
        button_style = """
            QPushButton {
                background-color: #3498db;
                color: white;
                border: none;
                border-radius: 5px;
                font-size: 16px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #2980b9;
            }
            QPushButton:pressed {
                background-color: #21618c;
            }
        """
        self.prev_button.setStyleSheet(button_style)
        self.play_button.setStyleSheet(button_style)
        self.next_button.setStyleSheet(button_style)
        
        # 볼륨 슬라이더 스타일
        self.volume_slider.setStyleSheet("""
            QSlider::groove:horizontal {
                border: 1px solid #bdc3c7;
                height: 6px;
                background: #34495e;
                border-radius: 3px;
            }
            QSlider::handle:horizontal {
                background: #e74c3c;
                border: 1px solid #c0392b;
                width: 16px;
                margin: -2px 0;
                border-radius: 8px;
            }
            QSlider::sub-page:horizontal {
                background: #e74c3c;
                border-radius: 3px;
            }
        """)
        
        # 버튼들을 레이아웃에 추가
        button_layout.addStretch()
        button_layout.addWidget(self.prev_button)
        button_layout.addWidget(self.play_button)
        button_layout.addWidget(self.next_button)
        button_layout.addStretch()
        button_layout.addWidget(QLabel("🔊"))
        button_layout.addWidget(self.volume_slider)
        
        control_layout.addLayout(button_layout)
        layout.addWidget(control_frame)
        
    def setup_connections(self):
        # 버튼 연결
        self.play_button.clicked.connect(self.play_pause)
        self.prev_button.clicked.connect(self.play_previous)
        self.next_button.clicked.connect(self.play_next)
        
        # 슬라이더 연결
        self.progress_slider.sliderMoved.connect(self.set_position)
        self.volume_slider.valueChanged.connect(self.set_volume)
        
        # 미디어 플레이어 연결
        self.media_player.positionChanged.connect(self.position_changed)
        self.media_player.durationChanged.connect(self.duration_changed)
        self.media_player.stateChanged.connect(self.state_changed)
        
        # 파일 목록 연결
        self.file_list.itemDoubleClicked.connect(self.play_selected_file)
        
    def add_files(self):
        files, _ = QFileDialog.getOpenFileNames(
            self, "비디오 파일 선택", "",
            "Video Files (*.mp4 *.avi *.mkv *.mov *.wmv *.flv *.webm);;All Files (*)"
        )
        for file in files:
            self.add_file_to_list(file)
            
    def add_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "폴더 선택")
        if folder:
            video_extensions = ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm']
            for root, dirs, files in os.walk(folder):
                for file in files:
                    if any(file.lower().endswith(ext) for ext in video_extensions):
                        file_path = os.path.join(root, file)
                        self.add_file_to_list(file_path)
                        
    def add_file_to_list(self, file_path):
        if file_path not in self.video_files:
            self.video_files.append(file_path)
            file_name = os.path.basename(file_path)
            self.file_list.addItem(file_name)
            
    def play_selected_file(self, item):
        index = self.file_list.row(item)
        if 0 <= index < len(self.video_files):
            self.current_file_index = index
            self.play_file(self.video_files[index])
            
    def play_file(self, file_path):
        url = QUrl.fromLocalFile(file_path)
        content = QMediaContent(url)
        self.media_player.setMedia(content)
        
        # FPS 추정 및 설정
        self.fps = self.estimate_fps_from_file(file_path)
        self.fps_label.setText(f"FPS: {self.fps:.2f}")
        
        self.play_pause()
        
    def play_pause(self):
        if self.media_player.state() == QMediaPlayer.PlayingState:
            self.media_player.pause()
        else:
            self.media_player.play()
            self.timer.start()
            
    def play_previous(self):
        if self.video_files:
            self.current_file_index = (self.current_file_index - 1) % len(self.video_files)
            self.play_file(self.video_files[self.current_file_index])
            self.file_list.setCurrentRow(self.current_file_index)
            
    def play_next(self):
        if self.video_files:
            self.current_file_index = (self.current_file_index + 1) % len(self.video_files)
            self.play_file(self.video_files[self.current_file_index])
            self.file_list.setCurrentRow(self.current_file_index)
            
    def set_position(self, position):
        self.media_player.setPosition(position)
        
    def set_volume(self, volume):
        self.media_player.setVolume(volume)
        
    def position_changed(self, position):
        self.progress_slider.setValue(position)
        self.update_time()
        
    def duration_changed(self, duration):
        self.progress_slider.setRange(0, duration)
        
        # 총 프레임 수 계산 및 업데이트
        if self.fps > 0 and duration > 0:
            total_seconds = duration / 1000.0
            self.total_frames = int(total_seconds * self.fps)
            self.total_frames_label.setText(str(self.total_frames))
            
            # 프레임 정보 초기화
            self.current_frame_label.setText("0")
        
    def state_changed(self, state):
        if state == QMediaPlayer.PlayingState:
            self.play_button.setText("⏸")
            self.timer.start()
        else:
            self.play_button.setText("▶")
            self.timer.stop()
            
    def update_time(self):
        current = self.media_player.position()
        total = self.media_player.duration()
        
        self.current_time_label.setText(self.format_time(current))
        self.total_time_label.setText(self.format_time(total))
        
        # 프레임 정보 업데이트
        self.update_frame_info(current, total)
        
    def update_frame_info(self, current_position, total_duration):
        """프레임 정보를 업데이트합니다."""
        if self.fps > 0:
            # 현재 프레임 계산 (밀리초를 초로 변환 후 FPS 곱하기)
            current_seconds = current_position / 1000.0
            current_frame = int(current_seconds * self.fps)
            
            # 총 프레임 계산
            total_seconds = total_duration / 1000.0
            total_frame = int(total_seconds * self.fps)
            
            self.current_frame_label.setText(str(current_frame))
            self.total_frames_label.setText(str(total_frame))
            
    def calculate_fps_from_duration(self, duration):
        """재생 시간으로부터 대략적인 FPS를 추정합니다."""
        # 일반적인 비디오 FPS 값들
        common_fps = [23.976, 24, 25, 29.97, 30, 50, 59.94, 60]
        
        if duration > 0:
            # 1분(60초) 기준으로 프레임 수를 추정
            estimated_frames_per_minute = 1500  # 일반적인 1분당 프레임 수
            estimated_fps = estimated_frames_per_minute / 60.0
            
            # 가장 가까운 일반적인 FPS 값 찾기
            closest_fps = min(common_fps, key=lambda x: abs(x - estimated_fps))
            return closest_fps
        
        return 30.0  # 기본값
        
    def estimate_fps_from_file(self, file_path):
        """파일 경로로부터 FPS를 추정합니다."""
        # 먼저 ffprobe로 정확한 FPS 정보를 얻으려고 시도
        try:
            fps = self.get_fps_with_ffprobe(file_path)
            if fps > 0:
                return fps
        except:
            pass
        
        # ffprobe가 실패하면 파일 확장자에 따른 일반적인 FPS 추정
        file_ext = os.path.splitext(file_path)[1].lower()
        
        fps_estimates = {
            '.mp4': 30.0,
            '.avi': 25.0,
            '.mkv': 24.0,
            '.mov': 30.0,
            '.wmv': 30.0,
            '.flv': 30.0,
            '.webm': 30.0
        }
        
        return fps_estimates.get(file_ext, 30.0)
        
    def get_fps_with_ffprobe(self, file_path):
        """ffprobe를 사용하여 비디오 파일의 FPS를 가져옵니다."""
        try:
            # ffprobe 명령어로 비디오 스트림 정보 가져오기
            cmd = [
                'ffprobe',
                '-v', 'quiet',
                '-print_format', 'json',
                '-show_streams',
                '-select_streams', 'v:0',  # 첫 번째 비디오 스트림
                file_path
            ]
            
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            
            if result.returncode == 0:
                data = json.loads(result.stdout)
                if 'streams' in data and len(data['streams']) > 0:
                    stream = data['streams'][0]
                    
                    # FPS 정보 추출 (r_frame_rate 또는 avg_frame_rate)
                    fps_str = stream.get('r_frame_rate', stream.get('avg_frame_rate', ''))
                    
                    if fps_str and '/' in fps_str:
                        num, den = map(int, fps_str.split('/'))
                        if den > 0:
                            return num / den
                            
        except (subprocess.TimeoutExpired, subprocess.CalledProcessError, 
                json.JSONDecodeError, KeyError, ValueError, FileNotFoundError):
            pass
            
        return 0.0  # 실패 시 0 반환
        
    def format_time(self, ms):
        if ms < 0:
            return "00:00"
        seconds = ms // 1000
        minutes = seconds // 60
        seconds = seconds % 60
        return f"{minutes:02d}:{seconds:02d}"

    def update_info_display(self):
        """선택된 정보에 따라 표시할 위젯을 업데이트합니다."""
        selected_info = self.info_combo.currentText()
        
        # 기존 위젯들 제거
        while self.info_display_layout.count():
            child = self.info_display_layout.takeAt(0)
            if child.widget():
                child.widget().setParent(None)
        
        # 선택된 정보에 따라 위젯 추가
        if selected_info == "시간 + 프레임":
            self.info_display_layout.addWidget(self.time_info_widget)
            self.info_display_layout.addWidget(self.frame_info_widget)
        elif selected_info == "시간만":
            self.info_display_layout.addWidget(self.time_info_widget)
        elif selected_info == "프레임만":
            self.info_display_layout.addWidget(self.frame_only_widget)

def main():
    app = QApplication(sys.argv)
    
    # 애플리케이션 스타일 설정
    app.setStyle('Fusion')
    
    # 다크 테마 스타일시트
    app.setStyleSheet("""
        QMainWindow {
            background-color: #2c3e50;
        }
        QWidget {
            background-color: #34495e;
            color: white;
        }
    """)
    
    player = VideoPlayer()
    player.show()
    
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
