import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QLineEdit,
                            QHBoxLayout, QComboBox, QLabel, QTreeWidget, QTreeWidgetItem)

class ValidationApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.current_episode = ""
        self.setWindowTitle("씬 리스트")
        self.setGeometry(100, 100, 600, 800)  # 너비 축소
        
        font = self.font()
        font.setPointSize(font.pointSize() + 2)
        self.setFont(font)

        # 메인 위젯 설정
        self.main_widget = QWidget()
        self.setCentralWidget(self.main_widget)
        layout = QVBoxLayout()
        
        # 콤보박스 영역
        combo_layout = QVBoxLayout()
        
        # 작품 선택
        show_layout = QHBoxLayout()
        show_layout.setSpacing(5)  # 라벨과 콤보박스 사이 간격을 5픽셀로 설정
        show_layout.addWidget(QLabel("작품:"))
        self.show_combo = QComboBox()
        self.show_combo.setFixedWidth(160)
        self.show_combo.addItem("작품 선택")
        self.show_combo.addItems(["BB", "GN", "BM", "KOTH", "Test", "Yeson_DANG", "Yeson_Test", "Yeson_Test_4K"])
        self.show_combo.currentTextChanged.connect(self.on_show_changed)
        show_layout.addWidget(self.show_combo)
        show_layout.addStretch()  # 오른쪽 여백을 채움
        combo_layout.addLayout(show_layout)
        
        # 시즌 선택
        season_layout = QHBoxLayout()
        season_layout.setSpacing(5)  # 라벨과 콤보박스 사이 간격을 5픽셀로 설정
        season_layout.addWidget(QLabel("시즌:"))
        self.season_combo = QComboBox()
        self.season_combo.setFixedWidth(160)
        self.season_combo.addItem("시즌 선택")
        self.season_combo.setEnabled(False)
        self.season_combo.currentTextChanged.connect(self.on_season_changed)
        season_layout.addWidget(self.season_combo)
        season_layout.addStretch()  # 오른쪽 여백을 채움
        combo_layout.addLayout(season_layout)
        
        # 화수 선택
        episode_layout = QHBoxLayout()
        episode_layout.setSpacing(5)  # 라벨과 콤보박스 사이 간격을 5픽셀로 설정
        episode_layout.addWidget(QLabel("화수:"))
        self.episode_combo = QComboBox()
        self.episode_combo.setFixedWidth(160)
        self.episode_combo.addItem("화수 선택")
        self.episode_combo.setEnabled(False)
        self.episode_combo.currentTextChanged.connect(self.on_episode_changed)
        episode_layout.addWidget(self.episode_combo)
        episode_layout.addStretch()  # 오른쪽 여백을 채움
        combo_layout.addLayout(episode_layout)
        
        layout.addLayout(combo_layout)

        # 계산 버튼과 결과 표시 영역
        calc_layout = QHBoxLayout()
        self.calc_button = QPushButton("선택 씬 계산")
        self.calc_button.setFixedWidth(100)
        self.calc_button.clicked.connect(self.calculate_selected_scenes)
        
        calc_layout.addWidget(self.calc_button)
        calc_layout.addWidget(QLabel("FEET :"))
        
        self.total_feet_display = QLineEdit()
        self.total_feet_display.setFixedWidth(100)
        self.total_feet_display.setReadOnly(True)
        calc_layout.addWidget(self.total_feet_display)
        calc_layout.addStretch()
        
        combo_layout.addLayout(calc_layout)        
        
        # QListWidget 대신 QTreeWidget 사용ss
        self.scene_list = QTreeWidget(self)
        self.scene_list.setHeaderLabels(['SEQ', 'SEQ FEET', '씬 이름', 'Frames', 'FEET'])
        self.scene_list.setColumnWidth(0, 70)  # SEQ 컬럼
        self.scene_list.setColumnWidth(1, 100)  # SEQ Frames 컬럼
        self.scene_list.setColumnWidth(2, 230)  # 씬 이름 컬럼
        self.scene_list.setColumnWidth(3, 70)   # Frames 컬럼
        self.scene_list.setColumnWidth(4, 70)   # FEET 컬럼
        self.scene_list.setSelectionMode(QTreeWidget.ExtendedSelection) 
        layout.addWidget(self.scene_list)
        
        self.main_widget.setLayout(layout)
        self.init_show_structure()

    def init_show_structure(self):
        """작품 구조 초기화"""
        self.show_paths = {
            "BB": {"base": "Bento_Project", "seasons": ["BB_Season13", "BB_Season14"]},
            "GN": {"base": "Bento_Project2/Great_North", "seasons": ["GN_Season4", "GN_Season5"]},
            "BM": {"base": "Titmouse/Big_Mouth", "seasons": ["BM_Season8"]},
            "KOTH": {"base": "Disney/KOTH", "seasons": ["KOTH_Season14", "KOTH_Season15"]},
            "Test": {"base": "Test", "seasons": ["TEST_SYSTEM"]},
            "Yeson_DANG": {"base": "Yeson_Test/DANG", "seasons": []},
            "Yeson_Test": {"base": "Yeson_Test", "seasons": []},
            "Yeson_Test_4K": {"base": "Yeson_Test_4K", "seasons": []}
        }

    def get_show_path(self, show):
        """작품별 경로 찾기"""
        if show == "작품 선택":
            return None
            
        possible_paths = [
            "/usadata2",
            "/usadata3",
            "/System/Volumes/Data/mnt/usadata2",
            "/System/Volumes/Data/mnt/usadata3",
            "/System/Volumes/data/mnt/usadata2",
            "/System/Volumes/data/mnt/usadata3",
            "/System/Volumes/Data/System/Volumes/Data/mnt/usadata2",
            "/System/Volumes/Data/System/Volumes/Data/mnt/usadata3",
            "/System/Volumes/data/System/Volumes/data/mnt/usadata2",
            "/System/Volumes/data/System/Volumes/data/mnt/usadata3"
        ]
        
        for base_path in possible_paths:
            if not os.path.exists(base_path):
                continue
                
            if show == "BB":
                project_path = os.path.join(base_path, "Bento_Project")
            elif show == "GN":
                project_path = os.path.join(base_path, "Bento_Project2", "Great_North")
            elif show == "BM":
                project_path = os.path.join(base_path, "Titmouse", "Big_Mouth")
            elif show == "KOTH":
                project_path = os.path.join(base_path, "Disney", "KOTH")
            elif show == "Test":
                project_path = os.path.join(base_path, "Test")
            elif show == "Yeson_DANG":
                if "usadata3" not in base_path:
                    continue
                project_path = os.path.join(base_path, "Yeson_Test", "DANG")
            elif show in ["Yeson_Test", "Yeson_Test_4K"]:
                if "usadata3" not in base_path:
                    continue
                project_path = os.path.join(base_path, show)
                
            if os.path.exists(project_path):
                return project_path
        return None

    def on_show_changed(self, show):
        """작품 선택 시 시즌 목록 업데이트"""
        self.scene_list.clear()  # scene_list로 수정
        self.season_combo.clear()
        self.episode_combo.clear()
        
        self.season_combo.addItem("시즌 선택")
        self.episode_combo.addItem("화수 선택")
        
        if show == "작품 선택":
            self.season_combo.setEnabled(False)
            self.episode_combo.setEnabled(False)
            return
            
        project_path = self.get_show_path(show)
        if project_path:
            if show == "BB":
                self.season_combo.setEnabled(True)
                seasons = ["BB_Season13", "BB_Season14"]
            elif show == "GN":
                self.season_combo.setEnabled(True)
                seasons = ["GN_Season4", "GN_Season5"]
            elif show == "BM":
                self.season_combo.setEnabled(True)
                seasons = ["BM_Season8"]
            elif show == "KOTH":
                self.season_combo.setEnabled(True)
                seasons = ["KOTH_Season14", "KOTH_Season15"]
            elif show == "Test":
                self.season_combo.setEnabled(True)
                seasons = ["TEST_SYSTEM"]
            elif show == "Yeson_DANG":
                self.season_combo.setEnabled(False)
                self.episode_combo.setEnabled(False)
                if os.path.exists(project_path):
                    scene_folders = []
                    for item in os.listdir(project_path):
                        if os.path.isdir(os.path.join(project_path, item)) and item.startswith('scene-'):
                            scene_folders.append(item)
                    self.scene_list.addItems(sorted(scene_folders))
                return
            elif show in ["Yeson_Test", "Yeson_Test_4K"]:
                self.season_combo.setEnabled(True)
                try:
                    seasons = []
                    for item in os.listdir(project_path):
                        if os.path.isdir(os.path.join(project_path, item)) and \
                           not item.startswith('.') and item != "DANG":
                            seasons.append(item)
                    seasons.sort()
                except Exception as e:
                    print(f"시즌 폴더 검색 중 오류: {e}")
                    seasons = []
            
            if show != "Yeson_DANG":
                self.season_combo.addItems(seasons)
            
            if show in ["Test", "Yeson_DANG", "Yeson_Test", "Yeson_Test_4K"]:
                self.episode_combo.setEnabled(False)
            else:
                self.episode_combo.setEnabled(True)

    def on_season_changed(self, season):
        """시즌 선택 시 화수 목록 업데이트"""
        self.scene_list.clear()
        if season == "시즌 선택":
            self.episode_combo.clear()
            self.episode_combo.addItem("화수 선택")
            self.episode_combo.setEnabled(False)
            return
            
        show = self.show_combo.currentText()
        project_path = self.get_show_path(show)
        
        if show in ["Test", "Yeson_Test", "Yeson_Test_4K"]:
            season_path = os.path.join(project_path, season)
            if os.path.exists(season_path):
                scene_folders = []
                for item in os.listdir(season_path):
                    if os.path.isdir(os.path.join(season_path, item)) and \
                       item.startswith('scene-'):
                        scene_folders.append(item)
                self.scene_list.addItems(sorted(scene_folders))
            self.episode_combo.setEnabled(False)
            return
            
        self.episode_combo.clear()
        self.episode_combo.addItem("화수 선택")
        self.episode_combo.setEnabled(True)
        
        if project_path:
            self.update_episode_list(show, season, project_path)

    def on_episode_changed(self, episode):
        """화수 선택 시 씬 폴더 목록 업데이트"""
        self.scene_list.clear()
        if episode == "화수 선택":
            return
            
        show = self.show_combo.currentText()
        season = self.season_combo.currentText()
        project_path = self.get_show_path(show)
        
        if project_path:
            episode_path = os.path.join(project_path, season, episode)
            if os.path.exists(episode_path):
                scene_folders = []
                for item in os.listdir(episode_path):
                    if os.path.isdir(os.path.join(episode_path, item)) and item.startswith("scene-"):
                        scene_folders.append(item)
                
                # 정렬된 씬 폴더 목록을 QTreeWidgetItem으로 추가
                for scene in sorted(scene_folders):
                    item = QTreeWidgetItem([scene])
                    self.scene_list.addTopLevelItem(item)
                
                # 프레임 정보 업데이트
                self.update_scene_list()

        self.show_combo.repaint()
        self.season_combo.repaint()
        self.episode_combo.repaint()                

    def update_episode_list(self, show, season, project_path):
        """화수 목록 업데이트"""
        if show == "BB":
            season_path = os.path.join(project_path, season)
            if os.path.exists(season_path):
                episodes = []
                for item in os.listdir(season_path):
                    if "Season13" in season and "DASA" in item:
                        episodes.append(item)
                    elif "Season14" in season and "EASA" in item:
                        episodes.append(item)
                self.episode_combo.addItems(sorted(episodes))
        elif show == "GN":
            if "GN_Season" in season:
                season_num = season.replace("GN_Season", "")
                season_path = os.path.join(project_path, f"GN_Season{season_num}")
                if os.path.exists(season_path):
                    episodes = []
                    for item in os.listdir(season_path):
                        if item.startswith(f"{season_num}LBW"):
                            episodes.append(item)
                    self.episode_combo.addItems(sorted(episodes))
        elif show == "BM":
            season_path = os.path.join(project_path, season)
            if os.path.exists(season_path):
                episodes = []
                for item in os.listdir(season_path):
                    if item.startswith("BM_8"):
                        episodes.append(item)
                self.episode_combo.addItems(sorted(episodes))
        elif show == "KOTH":
            season_path = os.path.join(project_path, season)
            if os.path.exists(season_path):
                episodes = []
                for item in os.listdir(season_path):
                    if "Season14" in season and item.startswith("EABE"):
                        episodes.append(item)
                    elif "Season15" in season and item.startswith("15"):
                        episodes.append(item)
                self.episode_combo.addItems(sorted(episodes))

    def format_feet_display(self, sheet_length):
        """FEET 값을 'XF YYf' 형식으로 변환"""
        try:
            feet, frames = str(sheet_length).split('.')
            return f"{feet}F {frames}f"
        except:
            return "0F 00f"

    def update_scene_list(self):
        """씬 리스트 업데이트"""
        episode = self.episode_combo.currentText()
        frames_info = self.get_frames_info(episode)
        show = self.show_combo.currentText()
        
        # 씬 정보를 담을 리스트 준비
        items = []
        special_items = []  # CHARACTERS, PROPS 씬을 위한 별도 리스트
        
        # 시퀀스별 프레임 합계 계산 및 FEET 계산
        seq_feet = {}
        for scene_name in frames_info:
            # CHARACTERS나 PROPS가 포함된 씬은 건너뛰기
            if 'CHARACTERS' in scene_name or 'PROPS' in scene_name:
                continue            
            if show == "BM":
                # BM 작품의 경우 첫 알파벳을 시퀀스로 사용
                scene_num = scene_name.replace('scene-', '')
                seq = scene_num[0]  # 첫 알파벳이 시퀀스
            elif show == "KOTH":
                # KOTH 작품의 경우 씬 번호 범위로 Act 구분
                scene_num = scene_name.replace('scene-', '')
                scene_number = int(scene_num)
                if scene_number < 300:
                    seq = "Act1"
                elif scene_number < 600:
                    seq = "Act2"
                else:
                    seq = "Act3"                
            else:
                # 다른 작품은 기존 방식대로 언더바로 구분
                seq = scene_name.split('_')[0]
            frames = int(frames_info[scene_name])
            if seq not in seq_feet:
                seq_feet[seq] = 0
            seq_feet[seq] += frames
        
        # 시퀀스별 FEET 값 계산
        for seq in seq_feet:
            total_feet = self.calculate_sheet_length(seq_feet[seq])
            seq_feet[seq] = self.format_feet_display(total_feet)
        
        # 현재 시퀀스 추적
        current_seq = None
        
        # 정렬된 씬 목록으로 아이템 생성
        for scene_name in sorted(frames_info.keys()):
        # CHARACTERS나 PROPS 씬은 별도로 처리
            if 'CHARACTERS' in scene_name or 'PROPS' in scene_name:
                special_item = QTreeWidgetItem([
                    "-",  # 시퀀스 없음
                    "-",  # 시퀀스 FEET 없음
                    scene_name,
                    str(frames),
                    feet_display
                ])
                special_items.append(special_item)
                continue
            if show == "BM":
                scene_num = scene_name.replace('scene-', '')
                seq = scene_num[0]
            elif show == "KOTH":
                scene_num = scene_name.replace('scene-', '')
                scene_number = int(scene_num)
                if scene_number < 300:
                    seq = "Act1"
                elif scene_number < 600:
                    seq = "Act2"
                else:
                    seq = "Act3"                
            else:
                seq = scene_name.split('_')[0]
            frames = frames_info[scene_name]
            sheet_length = self.calculate_sheet_length(frames)
            feet_display = self.format_feet_display(sheet_length)
            
            if seq != current_seq:
                # 새로운 시퀀스의 첫 씬
                current_seq = seq
                seq_display = seq.replace('scene-', '')
                seq_feet_display = seq_feet[seq]  # FEET 값 표시
            else:
                # 같은 시퀀스의 다음 씬들
                seq_display = ""
                seq_feet_display = ""
            
            item = QTreeWidgetItem([
                seq_display.replace('scene-', ''),
                seq_feet_display,
                scene_name,
                str(frames),
                feet_display
            ])
            items.append(item)
        
        # UI 업데이트 최소화를 위해 한 번에 추가
        self.scene_list.clear()
        self.scene_list.addTopLevelItems(items + special_items)  # 특수 씬을 마지막에 추가

    def calculate_selected_scenes(self):
        """선택된 씬들의 FEET 합계 계산"""
        selected_items = self.scene_list.selectedItems()
        if not selected_items:
            self.total_feet_display.setText("0F 00f")
            return
            
        total_frames = 0
        for item in selected_items:
            frames = int(item.text(3))  # Frames 컬럼의 값
            total_frames += frames
        
        total_feet = self.calculate_sheet_length(total_frames)
        feet_display = self.format_feet_display(total_feet)
        self.total_feet_display.setText(feet_display)

    def calculate_sheet_length(self, frames):
        """시트지 길이 계산"""
        try:
            frames = int(frames)
            # 1단계: frames/16 계산
            step1 = frames / 16
            
            # 2단계: 소수점 앞의 정수를 빼서 소수부분만 추출
            integer_part = int(step1)
            step2 = step1 - integer_part
            
            # 3단계: 소수부분에 16을 곱하고 정수부분의 소수점으로 사용
            decimal_part = int(step2 * 16)
            # 문자열로 직접 포맷팅하여 float 변환을 피함
            return f"{integer_part}.{decimal_part:02d}"
        except:
            return "0.00"

    def get_frames_info(self, episode):
        """scene.db에서 프레임 정보 가져오기"""
        frames_info = {}
        current_scene = None
        
        possible_db_paths = [
            f"/USA_DB/db_jobs/{episode}/scene.db",
            f"/System/Volumes/Data/mnt/USA_DB/db_jobs/{episode}/scene.db",
            f"/System/Volumes/data/mnt/USA_DB/db_jobs/{episode}/scene.db",
            f"/System/Volumes/Data/System/Volumes/Data/mnt/USA_DB/db_jobs/{episode}/scene.db",
            f"/System/Volumes/data/System/Volumes/data/mnt/USA_DB/db_jobs/{episode}/scene.db"
        ]
        
        if episode.startswith(('DASA', 'EASA')) or \
        episode.startswith(('4LBW', '5LBW')) or \
        episode.startswith('BM_8') or \
        episode.startswith(('EABE', '15')):
            
            # 각 경로를 순차적으로 시도
            for db_path in possible_db_paths:
                if os.path.exists(db_path):
                    try:
                        dbu_command = f"/Applications/Toon\ Boom\ Harmony\ 21.1\ Premium/Harmony\ 21.1\ Premium.app/Contents/tba/macosx/bin/dbu -l -r {db_path}"
                        result = os.popen(dbu_command).read()
                        
                        for line in result.splitlines():
                            if 'Path:' in line:
                                path = line.split('Path:')[1].strip()
                                current_scene = os.path.basename(path)
                            elif 'Frames:' in line and current_scene:
                                frames = line.split('Frames:')[1].strip()
                                frames_info[current_scene] = frames
                        
                        # 성공적으로 데이터를 읽었으면 반복 중단
                        if frames_info:
                            break
                    except Exception as e:
                        print(f"프레임 정보 추출 중 오류 발생: {e}")
                        continue
        
        return frames_info


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ValidationApp()
    window.show()
    sys.exit(app.exec_())