import panel as pn
import webview
import os
import numpy as np
from hdf5 import HDF5Reader
from table import DataTable
from list import DataList
from graph import GraphPanel

class HDF5ViewerUI:
    """전체 UI 통합 클래스"""
    
    def __init__(self):
        self.reader = HDF5Reader()
        self.template = None  # create_layout()에서 설정됨
        
        # 컴포넌트 생성
        self.data_table = DataTable(self.reader)
        self.data_list = DataList(self.reader)
        self.graph_panel = GraphPanel()
        
        # Export 팝업 오버레이 컨테이너 (비어있을 때는 클릭 방해하지 않음)
        self.export_overlay = pn.Column(
            sizing_mode='stretch_both',
            styles={
                'pointer-events': 'none',
                'position': 'absolute',
                'top': '0',
                'left': '0',
                'width': '100%',
                'height': '100%',
                'z-index': '999'
            }
        )
        
        # 그래프 선택 시 테이블/리스트 필터링 연결
        self.graph_panel.set_selection_callback(self._on_graph_selection)
        
        # 테이블에서 Tag 업데이트 시 그래프 패널의 Tag 드롭다운 업데이트
        self.data_table.on_tag_update_callback = self._on_tag_update
        
        # 테이블에서 Export 버튼 클릭 시 콜백
        self.data_table.on_export_callback = self._on_export
        
        # Particle 통계 표시
        self.stats_bar = pn.pane.HTML(
            self._build_stats_html(None),
            sizing_mode='stretch_width',
            margin=(0, 10)
        )
        
        self._create_widgets()
        self._setup_callbacks()
    
    def _on_graph_selection(self, selected_indices):
        """그래프에서 데이터 선택 시 테이블/리스트 필터링"""
        print(f"[MainUI] _on_graph_selection called with {len(selected_indices)} indices")
        self.data_table.filter_data(selected_indices)
        self.data_list.filter_data(selected_indices)
        self._update_stats()
    
    def _on_tag_update(self):
        """테이블에서 Tag 업데이트 시 그래프 패널의 Tag 드롭다운 업데이트"""
        print(f"[MainUI] _on_tag_update called")
        self.graph_panel.update_tag_dropdowns()
    
    def _on_export(self):
        """Export 버튼 클릭 시 팝업 표시 및 Export 실행"""
        from export_popup import ExportPopup
        from html_export import DataExporter
        
        # 기본값 결정
        if self.reader.file_path:
            default_folder_name = os.path.splitext(os.path.basename(self.reader.file_path))[0]
            default_location = os.path.dirname(self.reader.file_path)
        else:
            default_folder_name = "export"
            default_location = os.getcwd()
        
        def on_cancel():
            """Cancel 버튼 클릭 시 오버레이 닫기"""
            self.export_overlay.clear()
            self.export_overlay.styles = {
                'pointer-events': 'none',
                'position': 'relative'
            }
            if hasattr(self, 'template') and self.template:
                self.template.close_modal()
        
        def on_confirm(folder_name, folder_location):
            print(f"[MainUI] Export confirmed: folder='{folder_name}', location='{folder_location}'")
            
            # 오버레이 닫기
            self.export_overlay.clear()
            self.export_overlay.styles = {
                'pointer-events': 'none',
                'position': 'relative'
            }
            if hasattr(self, 'template') and self.template:
                self.template.close_modal()
            
            # Export 데이터 준비
            if self.data_table.current_df is None:
                return
            
            # 전체 데이터 export
            df = self.data_table.current_df
            
            if len(df) == 0:
                print("[MainUI] No data to export")
                return
            
            # DataExporter 생성
            exporter = DataExporter(self.reader)
            
            # 그래프 이미지 수집
            graph_images = self.graph_panel.get_graph_images()
            exporter.set_graph_images(graph_images)
            
            # Export 실행
            success, result = exporter.export(df, folder_name, folder_location)
            
            if success:
                print(f"[MainUI] Export successful: {result}")
                pn.state.notifications.success(
                    f"Exported to: {os.path.basename(result)}",
                    duration=5000
                )
            else:
                print(f"[MainUI] Export failed: {result}")
                pn.state.notifications.error(
                    f"Export failed: {result}",
                    duration=5000
                )
        
        # Export 팝업 생성 및 표시
        popup = ExportPopup(
            on_confirm,
            on_cancel,
            default_folder_name=default_folder_name,
            default_location=default_location
        )
        popup_overlay = popup.show_as_overlay(None)
        
        # 오버레이에 팝업 추가
        self.export_overlay.clear()
        self.export_overlay.append(popup_overlay)
        
        # pointer-events 활성화 (오버레이가 클릭 가능하도록)
        self.export_overlay.styles = {
            'pointer-events': 'auto',
            'position': 'relative'
        }
        
        # 모달 열기
        if hasattr(self, 'template') and self.template:
            self.template.open_modal()
    
    def _build_stats_html(self, df):
        """Particle 통계 HTML 생성"""
        if df is None or len(df) == 0:
            return (
                '<div style="font-size:14px; color:#555; padding:4px 0; '
                'white-space:nowrap; font-size:18px;">'
                'No data</div>'
            )
        
        total = len(df)
        
        # AED 컬럼 찾기
        aed_col = None
        for col in df.columns:
            if col.upper() == 'AED':
                aed_col = col
                break
        
        if aed_col and aed_col in df.columns:
            aed = df[aed_col].dropna()
            if len(aed) > 0:
                avg_aed = aed.mean()
                min_aed = aed.min()
                mid_aed = aed.median()
                max_aed = aed.max()
                stats_text = (
                    f'Total: <b>{total:,}</b> &nbsp;&nbsp; '
                    f'Average AED: <b>{avg_aed:.2f}</b> &nbsp;&nbsp; '
                    f'Min AED: <b>{min_aed:.2f}</b> &nbsp;&nbsp; '
                    f'Mid AED: <b>{mid_aed:.2f}</b> &nbsp;&nbsp; '
                    f'Max AED: <b>{max_aed:.2f}</b>'
                )
            else:
                stats_text = f'Total: <b>{total:,}</b>'
        else:
            stats_text = f'Total: <b>{total:,}</b>'
        
        return (
            f'<div style="font-size:18px; color:#555; padding:4px 0; '
            f'white-space:nowrap;">'
            f'{stats_text}</div>'
        )
    
    def _update_stats(self):
        """현재 필터 상태에 맞게 통계 업데이트"""
        if self.data_table.current_df is None:
            self.stats_bar.object = self._build_stats_html(None)
            return
        
        if self.data_table.filtered_indices is not None:
            df = self.data_table.current_df.loc[self.data_table.filtered_indices]
        else:
            df = self.data_table.current_df
        
        self.stats_bar.object = self._build_stats_html(df)
    
    def _create_widgets(self):
        """위젯 생성"""
        # 파일 선택 버튼
        self.file_button = pn.widgets.Button(
            name='Select File', 
            button_type='primary',
            width=150
        )
        
        # 선택된 파일 경로 표시
        self.file_path_input = pn.widgets.TextInput(
            name='Selected File',
            disabled=True,
            placeholder='HDF5 파일을 선택해주세요'
        )
        
        # 데이터 정보 표시
        self.data_info = pn.pane.Markdown(
            """
## Data Info
            """,
            sizing_mode='stretch_width'
        )
    
    def _setup_callbacks(self):
        """콜백 설정"""
        self.file_button.on_click(self._on_file_select)
    
    def _on_file_select(self, event):
        """파일 선택 다이얼로그"""
        result = webview.windows[0].create_file_dialog(
            webview.OPEN_DIALOG,
            file_types=('HDF5 Files (*.h5;*.hdf5)', 'All Files (*.*)')
        )
        
        if result and len(result) > 0:
            file_path = result[0]
            self._load_file(file_path)
    
    def _load_file(self, file_path: str):
        """HDF5 파일 로딩"""
        self.data_info.object = "## Opening File..."
        
        success = self.reader.open_file(file_path)
        
        if not success:
            self.data_info.object = """
## Data Info

Unable to open file, make sure it is a valid HDF5 file
"""
            return
        
        # 파일 경로 표시
        self.file_path_input.value = file_path
        
        file_name = os.path.basename(file_path)
        particle_count = self.reader.get_total_particle_count()
        
        self.data_info.object = f"""
## Data Info

Loading Data...
- **Particles**: {particle_count:,}
"""
        
        # 데이터프레임 가져오기
        df = self.reader.get_particle_dataframe()
        
        if df.empty:
            self.data_info.object = """
## Data Info

Data not found
"""
            return
        
        # 숫자 컬럼을 소숫점 둘째자리로 반올림
        numeric_columns = df.select_dtypes(include=[np.number]).columns
        df[numeric_columns] = df[numeric_columns].round(2)
        
        # Image 컬럼 생성
        if self.reader.has_images():
            print("이미지 로딩 시작...")
            images = []
            
            total_rows = len(df)
            chunk_size = 100
            
            for idx in range(total_rows):
                img_html = self.reader.get_particle_image(idx)
                
                if img_html:
                    images.append(img_html)
                else:
                    images.append(
                        '<div style="width:68px;height:68px;background:#fee;'
                        'color:red;display:flex;align-items:center;'
                        'justify-content:center;">❌</div>'
                    )
                
                if (idx + 1) % chunk_size == 0 or idx == total_rows - 1:
                    progress = (idx + 1) * 100 // total_rows
                    self.data_info.object = f"""
## Data Info

Loading Images... {progress}%
- **File**: `{file_name}`
- **Loaded**: {idx + 1:,} / {total_rows:,}
"""
            
            df.insert(0, 'Image', images)
            print("이미지 로딩 완료!")
        
        # Tag 컬럼이 없으면 빈 컬럼 추가, 있으면 Image 다음에 위치시키기
        if 'Tag' not in df.columns:
            # Tag 컬럼 추가 (Image 다음 위치)
            insert_pos = 1 if 'Image' in df.columns else 0
            df.insert(insert_pos, 'Tag', '')
        else:
            # Tag 컬럼이 이미 있으면 Image 다음으로 이동
            if 'Image' in df.columns:
                tag_col = df.pop('Tag')
                df.insert(1, 'Tag', tag_col)
        
        # 테이블 업데이트 (컬럼 정보 설정)
        self.data_table.update_data(df)
        
        # 리스트 업데이트
        self.data_list.update_data(df)
        
        # 그래프 업데이트 (콜백으로 테이블/리스트 필터링)
        self.graph_panel.update_data(df)
        
        # 통계 업데이트
        self._update_stats()
        
        # Attributes 읽기
        attrs = self.reader.get_file_attributes()
        
        # Data Info 생성
        info_text = f"""
## Data Info

- **File**: `{file_name}`
- **Total Particles**: {len(df):,}
"""
        
        # AED 통계 추가
        aed_col = None
        for col in df.columns:
            if col.upper() == 'AED':
                aed_col = col
                break
        
        if aed_col and aed_col in df.columns:
            aed = df[aed_col].dropna()
            if len(aed) > 0:
                info_text += f"- **Total Average AED**: {aed.mean():.2f}\n"
                info_text += f"- **Total Min AED**: {aed.min():.2f}\n"
                info_text += f"- **Total Mid AED**: {aed.median():.2f}\n"
                info_text += f"- **Total Max AED**: {aed.max():.2f}\n"
        
        # Attributes 추가
        if attrs:
            for key, value in attrs.items():
                # 값이 너무 길면 자르기
                value_str = str(value)
                if len(value_str) > 50:
                    value_str = value_str[:47] + "..."
                info_text += f"- **{key}**: {value_str}\n"
        
        self.data_info.object = info_text
    
    def create_layout(self):
        """전체 레이아웃 생성"""
        # List/Table 탭 생성
        data_tabs = pn.Tabs(
            ('List', self.data_list.get_layout()),
            ('Table', self.data_table.get_layout()),
            sizing_mode='stretch_both',
            dynamic=True,
            margin=0
        )
        
        # Tab 위의 버튼 행 (왼쪽: 통계, 오른쪽: 버튼)
        button_row = pn.Row(
            self.stats_bar,
            pn.layout.HSpacer(),
            self.data_table.save_button,
            self.data_table.export_button,
            sizing_mode='stretch_width',
            align='center',
            margin=(5, 10, 5, 10)
        )
        
        # Data 영역
        data_section = pn.Column(
            button_row,
            data_tabs,
            sizing_mode='stretch_both',
            margin=0
        )
        
        version_label = pn.pane.HTML(
            '<span style="color: rgba(255,255,255,0.6); font-size: 12px; '
            'margin-right: 8px; white-space: nowrap;">v0.1.0</span>',
            sizing_mode='fixed',
            align='center'
        )
        
        template = pn.template.FastListTemplate(
            title='FlowInsight',
            theme_toggle=False,
            header=[version_label],
            sidebar=[
                pn.Column(
                    pn.pane.Markdown("## Select File"),
                    self.file_button,
                    self.file_path_input,
                    pn.layout.Divider(),
                    self.data_info,
                    pn.layout.Divider(),
                    pn.pane.Markdown("## Column Visibility"),
                    self.data_table.column_selector,
                    sizing_mode='stretch_width'
                )
            ],
            main=[
                self.graph_panel.get_layout(),
                data_section,
            ],
            modal=[self.export_overlay],
        )
        self.export_overlay.visible = True
        
        # template 참조 저장 (모달 open/close에 필요)
        self.template = template
        
        return template