import fitz  # PyMuPDF
from PIL import Image, ImageTk
import io
import os
import tkinter as tk
from tkinter import ttk, messagebox
import platform
import subprocess

class PDFPreviewManager:
    """PDF 미리보기 관리 클래스"""
    
    def __init__(self):
        self.preview_cache = {}  # 미리보기 이미지 캐싱
    
    def get_pdf_info(self, pdf_path: str) -> dict:
        """PDF 기본 정보 추출"""
        try:
            if not pdf_path or not os.path.exists(pdf_path):
                return {
                    'error': 'PDF 파일을 찾을 수 없습니다.', 
                    'page_count': 0, 
                    'file_size': 0,
                    'is_encrypted': False,
                    'title': '',
                    'author': '',
                    'creation_date': '',
                    'file_name': os.path.basename(pdf_path) if pdf_path else '',
                    'file_path': pdf_path or ''
                }
            
            doc = fitz.open(pdf_path)
            metadata = doc.metadata or {}
            info = {
                'page_count': doc.page_count,
                'file_size': os.path.getsize(pdf_path),
                'is_encrypted': doc.is_encrypted,
                'title': metadata.get('title', '') or '',
                'author': metadata.get('author', '') or '',
                'creation_date': metadata.get('creationDate', '') or '',
                'file_name': os.path.basename(pdf_path),
                'file_path': pdf_path
            }
            doc.close()
            return info
        except Exception as e:
            return {
                'error': str(e), 
                'page_count': 0, 
                'file_size': 0,
                'is_encrypted': False,
                'title': '',
                'author': '',
                'creation_date': '',
                'file_name': os.path.basename(pdf_path) if pdf_path else '',
                'file_path': pdf_path or ''
            }
    
    def create_preview_thumbnail(self, pdf_path: str, target_size=(250, 350)) -> Image.Image:
        """PDF 첫 페이지 썸네일 생성"""
        cache_key = f"{pdf_path}_{target_size}"
        
        # 캐시에 있으면 반환
        if cache_key in self.preview_cache:
            return self.preview_cache[cache_key]
        
        try:
            doc = fitz.open(pdf_path)
            if doc.page_count == 0:
                doc.close()
                return None
                
            page = doc[0]  # 첫 페이지
            
            # 미리보기 크기에 맞게 해상도 계산
            zoom_x = target_size[0] / page.rect.width
            zoom_y = target_size[1] / page.rect.height
            zoom = min(zoom_x, zoom_y) * 1.5  # 약간 높은 해상도
            
            mat = fitz.Matrix(zoom, zoom)
            pix = page.get_pixmap(matrix=mat)
            img_data = pix.tobytes("png")
            
            # PIL Image로 변환
            image = Image.open(io.BytesIO(img_data))
            image.thumbnail(target_size, Image.Resampling.LANCZOS)
            
            doc.close()
            
            # 캐시에 저장
            self.preview_cache[cache_key] = image
            return image
            
        except Exception as e:
            print(f"미리보기 생성 실패 ({pdf_path}): {e}")
            return None
    
    def format_file_size(self, size_bytes: int) -> str:
        """파일 크기를 읽기 쉬운 형태로 변환"""
        if size_bytes < 1024:
            return f"{size_bytes}B"
        elif size_bytes < 1024**2:
            return f"{size_bytes/1024:.1f}KB"
        else:
            return f"{size_bytes/(1024**2):.1f}MB"
    
    def clear_cache(self):
        """캐시 클리어"""
        self.preview_cache.clear()
    
    def open_file_with_system(self, pdf_path: str) -> bool:
        """시스템 기본 프로그램으로 파일 열기"""
        try:
            if platform.system() == 'Windows':
                os.startfile(pdf_path)
            elif platform.system() == 'Darwin':  # macOS
                subprocess.run(['open', pdf_path])
            else:  # Linux
                subprocess.run(['xdg-open', pdf_path])
            return True
        except Exception as e:
            print(f"파일 열기 실패 ({pdf_path}): {e}")
            return False

class PDFPreviewDialog:
    """PDF 미리보기 다이얼로그"""
    
    def __init__(self, parent, pdf_path: str, employee_name: str, preview_manager: PDFPreviewManager):
        self.parent = parent
        self.pdf_path = pdf_path
        self.employee_name = employee_name
        self.preview_manager = preview_manager
        
        # PDF 정보 가져오기
        self.pdf_info = preview_manager.get_pdf_info(pdf_path)
        
        # 다이얼로그 창 생성
        self.window = tk.Toplevel(parent)
        self.window.title(f"미리보기 - {employee_name}")
        self.window.geometry("450x650")
        self.window.resizable(True, True)
        
        # 창을 모달로 설정
        self.window.transient(parent)
        self.window.grab_set()
        
        # 창을 화면 중앙에 위치
        self.center_window()
        
        self.setup_ui()
    
    def center_window(self):
        """창을 화면 중앙에 위치시키기"""
        self.window.update_idletasks()
        width = self.window.winfo_width()
        height = self.window.winfo_height()
        pos_x = (self.window.winfo_screenwidth() // 2) - (width // 2)
        pos_y = (self.window.winfo_screenheight() // 2) - (height // 2)
        self.window.geometry(f'{width}x{height}+{pos_x}+{pos_y}')
    
    def setup_ui(self):
        """UI 구성"""
        main_frame = ttk.Frame(self.window, padding=10)
        main_frame.pack(fill='both', expand=True)
        
        # 상단: 파일 정보
        info_frame = ttk.LabelFrame(main_frame, text="📋 파일 정보", padding=10)
        info_frame.pack(fill='x', pady=(0, 10))
        
        # 정보 표시
        info_grid = ttk.Frame(info_frame)
        info_grid.pack(fill='x')
        
        # 파일명
        ttk.Label(info_grid, text="파일명:", font=('맑은 고딕', 9, 'bold')).grid(
            row=0, column=0, sticky='w', padx=(0, 10)
        )
        ttk.Label(info_grid, text=self.pdf_info.get('file_name', '알 수 없음')).grid(
            row=0, column=1, sticky='w'
        )
        
        # 직원명
        ttk.Label(info_grid, text="직원명:", font=('맑은 고딕', 9, 'bold')).grid(
            row=1, column=0, sticky='w', padx=(0, 10), pady=2
        )
        ttk.Label(info_grid, text=self.employee_name).grid(
            row=1, column=1, sticky='w', pady=2
        )
        
        # 페이지 수
        page_count = self.pdf_info.get('page_count', 0)
        ttk.Label(info_grid, text="페이지 수:", font=('맑은 고딕', 9, 'bold')).grid(
            row=2, column=0, sticky='w', padx=(0, 10), pady=2
        )
        ttk.Label(info_grid, text=f"{page_count}페이지").grid(
            row=2, column=1, sticky='w', pady=2
        )
        
        # 파일 크기
        file_size = self.preview_manager.format_file_size(self.pdf_info.get('file_size', 0))
        ttk.Label(info_grid, text="파일 크기:", font=('맑은 고딕', 9, 'bold')).grid(
            row=3, column=0, sticky='w', padx=(0, 10), pady=2
        )
        ttk.Label(info_grid, text=file_size).grid(
            row=3, column=1, sticky='w', pady=2
        )
        
        # 암호화 상태
        if self.pdf_info.get('is_encrypted'):
            ttk.Label(info_grid, text="보안:", font=('맑은 고딕', 9, 'bold')).grid(
                row=4, column=0, sticky='w', padx=(0, 10), pady=2
            )
            security_label = ttk.Label(info_grid, text="🔒 비밀번호 보호됨", foreground='orange')
            security_label.grid(row=4, column=1, sticky='w', pady=2)
        
        # 중앙: 미리보기 이미지
        preview_frame = ttk.LabelFrame(main_frame, text="📖 첫 페이지 미리보기", padding=10)
        preview_frame.pack(fill='both', expand=True, pady=(0, 10))
        
        # 스크롤 가능한 캔버스 생성
        canvas_frame = ttk.Frame(preview_frame)
        canvas_frame.pack(fill='both', expand=True)
        
        self.canvas = tk.Canvas(canvas_frame, bg='white', relief='sunken', bd=2)
        scrollbar_v = ttk.Scrollbar(canvas_frame, orient='vertical', command=self.canvas.yview)
        scrollbar_h = ttk.Scrollbar(canvas_frame, orient='horizontal', command=self.canvas.xview)
        
        self.canvas.configure(yscrollcommand=scrollbar_v.set, xscrollcommand=scrollbar_h.set)
        
        # 미리보기 이미지 로드 및 표시
        self.load_preview_image()
        
        # 그리드 배치
        self.canvas.grid(row=0, column=0, sticky='nsew')
        scrollbar_v.grid(row=0, column=1, sticky='ns')
        scrollbar_h.grid(row=1, column=0, sticky='ew')
        
        canvas_frame.grid_rowconfigure(0, weight=1)
        canvas_frame.grid_columnconfigure(0, weight=1)
        
        # 하단: 버튼들
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill='x', pady=(10, 0))
        
        # 버튼 배치
        ttk.Button(button_frame, text="📂 시스템으로 열기", 
                  command=self.open_with_system).pack(side='left', padx=(0, 5))
        ttk.Button(button_frame, text="📁 폴더 열기", 
                  command=self.open_folder).pack(side='left', padx=5)
        ttk.Button(button_frame, text="🔄 새로고침", 
                  command=self.refresh_preview).pack(side='left', padx=5)
        
        # 오른쪽에 닫기 버튼
        ttk.Button(button_frame, text="닫기", 
                  command=self.close_dialog).pack(side='right')
    
    def load_preview_image(self):
        """미리보기 이미지 로드"""
        try:
            if 'error' in self.pdf_info:
                # 오류 메시지 표시
                self.canvas.create_text(200, 100, 
                                      text=f"미리보기를 생성할 수 없습니다.\n{self.pdf_info['error']}", 
                                      fill='red', font=('맑은 고딕', 12), anchor='center')
                return
            
            # 미리보기 이미지 생성
            thumbnail = self.preview_manager.create_preview_thumbnail(self.pdf_path, (350, 500))
            
            if thumbnail:
                # PIL Image를 PhotoImage로 변환
                self.photo = ImageTk.PhotoImage(thumbnail)
                
                # 캔버스에 이미지 표시
                self.canvas.delete("all")  # 기존 내용 제거
                self.canvas.create_image(thumbnail.width//2, thumbnail.height//2, 
                                       image=self.photo, anchor='center')
                
                # 스크롤 영역 설정
                self.canvas.configure(scrollregion=self.canvas.bbox("all"))
                
            else:
                # 미리보기 실패 메시지
                self.canvas.create_text(200, 100, 
                                      text="미리보기를 생성할 수 없습니다.\nPDF 파일이 손상되었거나\n지원하지 않는 형식일 수 있습니다.", 
                                      fill='red', font=('맑은 고딕', 12), anchor='center')
                
        except Exception as e:
            # 예외 발생시 오류 메시지 표시
            self.canvas.create_text(200, 100, 
                                  text=f"미리보기 로드 실패:\n{str(e)}", 
                                  fill='red', font=('맑은 고딕', 12), anchor='center')
    
    def open_with_system(self):
        """시스템 기본 프로그램으로 열기"""
        success = self.preview_manager.open_file_with_system(self.pdf_path)
        if not success:
            messagebox.showerror("오류", "파일을 열 수 없습니다.\n기본 PDF 뷰어가 설치되어 있는지 확인해주세요.")
    
    def open_folder(self):
        """파일이 있는 폴더 열기"""
        try:
            folder_path = os.path.dirname(self.pdf_path)
            if platform.system() == 'Windows':
                subprocess.run(['explorer', '/select,', self.pdf_path])
            elif platform.system() == 'Darwin':  # macOS
                subprocess.run(['open', '-R', self.pdf_path])
            else:  # Linux
                subprocess.run(['xdg-open', folder_path])
        except Exception as e:
            messagebox.showerror("오류", f"폴더를 열 수 없습니다:\n{str(e)}")
    
    def refresh_preview(self):
        """미리보기 새로고침"""
        # 캐시에서 제거
        cache_key = f"{self.pdf_path}_(350, 500)"
        if cache_key in self.preview_manager.preview_cache:
            del self.preview_manager.preview_cache[cache_key]
        
        # PDF 정보 다시 로드
        self.pdf_info = self.preview_manager.get_pdf_info(self.pdf_path)
        
        # 미리보기 이미지 다시 로드
        self.load_preview_image()
        
        messagebox.showinfo("새로고침", "미리보기가 새로고침되었습니다.")
    
    def close_dialog(self):
        """다이얼로그 닫기"""
        self.window.grab_release()  # 모달 해제
        self.window.destroy()