#===========================================================================================
#		PDF to Images Converter (with GUI)
#
#Home:		https://www.sky-deep.com
#Author:	SKD Tech Group
#License:	This project is licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
#===========================================================================================
from hmac import new
from operator import ne
import fitz  # PyMuPDF
from PIL import Image, ImageOps
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
from tkinterdnd2 import DND_FILES, TkinterDnD
from pdf2docx import Converter
import re
from natsort import natsorted

cancel_event = threading.Event()


class PdfToImagesConverter:
    def __init__(self, pdf_path, output_folder, dpi=300, colorspace="RGB"):
        self.pdf_path = pdf_path
        self.output_folder = output_folder
        self.dpi = dpi
        self.colorspace = colorspace
        # self.ensure_output_folder_exists()

    def ensure_output_folder_exists(self, path):
        """确保输出文件夹存在"""
        if not os.path.exists(path):
            os.makedirs(path)

    def convert_pdf_to_images(self, input_path, output_path, progress_callback=None, log_callback=None):
        """将PDF文件转换为图像"""
        try:
            pdf_document = fitz.open(input_path)
            total_pages = len(pdf_document)
            self.ensure_output_folder_exists(output_path)
            for page_number in range(total_pages):
                # print('当前状态：', cancel_event.is_set())
                # if cancel_event.is_set():
                #     break
                log_message = f"进行中：Page {page_number + 1} ..."
                print(log_message)
                if log_callback:
                    log_callback(log_message)

                page = pdf_document.load_page(page_number)  # 加载页面
                pix = page.get_pixmap(matrix=fitz.Matrix(
                    self.dpi / 72, self.dpi / 72), colorspace=self.colorspace)  # 获取页面的像素图

                # 将像素图转换为PIL图像
                img = Image.frombytes(
                    "RGB", [pix.width, pix.height], pix.samples)

                # 保存图片
                img_path = os.path.join(
                    output_path, f"{page_number + 1}_page.png")
                img.save(img_path)
                # log_message = f"Page {page_number + 1} converted and saved in {os.path.basename(output_path)}"

                if progress_callback:
                    progress_callback(page_number + 1, total_pages)

            # if not cancel_event.is_set():
            #     messagebox.showinfo("完成", "PDF转换为图像完成！")
            # else:
            #     messagebox.showinfo("取消", "PDF转换已取消！")
        except Exception as e:
            if log_callback:
                log_callback(f"错误: {str(e)}")
            messagebox.showerror("错误", f"错误: {str(e)}")
        finally:
            cancel_event.clear()

    def run(self, progress_callback=None, log_callback=None):
        paths = self.pdf_path.split(';')

        for path in paths:
            if path.endswith('.pdf'):
                output_path = os.path.join(
                    self.output_folder, os.path.basename(path).replace('.pdf', '')+"_images")
                self.convert_pdf_to_images(
                    path, output_path, progress_callback, log_callback)

        if log_callback:
            log_callback("转换成功！")
        messagebox.showinfo("完成", "PDF转图片成功！")


class PdfToWordConverter:
    def __init__(self, pdf_path, word_path):
        self.pdf_path = pdf_path
        self.word_path = word_path

    def convert_pdf_to_word(self, input_path, output_path, log_callback=None):
        try:

            # log_callback(
            #        f"开始转({os.path.basename(input_path)})为Word({os.path.basename(output_path)})...")

            if log_callback:
                log_callback(f"PDF 转 word 进行中，请稍等...")
            cv = Converter(input_path)
            cv.convert(output_path, start=0, end=None)
            cv.close()
        except Exception as e:
            if log_callback:
                log_callback(f"错误: {str(e)}")
            messagebox.showerror("错误", f"{str(e)}")
        finally:
            cancel_event.clear()

    def run(self, log_callback=None):
        paths = self.pdf_path.split(';')

        for path in paths:
            if path.endswith('.pdf'):
                filename_without_ext, _ = os.path.splitext(path)
                output_path = os.path.join(
                    self.word_path, f"{os.path.basename(filename_without_ext)}.docx")
                self.convert_pdf_to_word(
                    path, output_path, log_callback)

        if log_callback:
            log_callback("转换成功！")
        messagebox.showinfo("完成", "PDF转word成功！")


class ImagesToPdfConverter:
    def __init__(self, image_paths, pdf_path):
        self.image_paths = image_paths
        self.pdf_path = pdf_path

    def apply_orientation(self, image):
        """
        Apply the EXIF orientation to the image.
        """
        # exif = image.getexif()
        # if exif is not None:

        #     orientation = exif.get(0x0112, 1)
        #     if orientation == 2:
        #         image = image.transpose(Image.FLIP_LEFT_RIGHT)
        #     elif orientation == 3:
        #         image = image.rotate(180)
        #     elif orientation == 4:
        #         image = image.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)
        #     elif orientation == 5:
        #         image = image.rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)
        #     elif orientation == 6:
        #         image = image.rotate(-90)
        #     elif orientation == 7:
        #         image = image.rotate(90).transpose(Image.FLIP_LEFT_RIGHT)
        #     elif orientation == 8:
        #         image = image.rotate(90)
        return ImageOps.exif_transpose(image)

    def fit_image_to_page(self, image, page_size=(595, 842)):
        """
        缩放图片并添加背景填充，适配 PDF 页面。
        page_size: PDF 页面大小，单位为点（1点 = 1/72英寸）。
        """
        page_width, page_height = page_size
        img_width, img_height = image.size

        # 计算缩放比例，适配页面
        # scale = min(page_width / img_width, page_height / img_height)
        new_width = img_width
        new_height = img_height

        while new_width > page_width or new_height > page_height:
            new_width = new_width * 0.9
            new_height = new_height * 0.9

        new_height = int(new_height)
        new_width = int(new_width)

        # 调整图片尺寸
        resized_image = image.resize((new_width, new_height), Image.LANCZOS)

        # 创建白色背景画布
        canvas = Image.new('RGB', (page_width, page_height), (255, 255, 255))

        # 计算图片居中位置
        offset_x = (page_width - new_width) // 2
        offset_y = (page_height - new_height) // 2

        # 将图片粘贴到画布上
        canvas.paste(resized_image, (offset_x, offset_y))

        return canvas

    def convert_images_to_pdf(self, input_paths, output_path, log_callback=None):
        try:
            if log_callback:
                log_callback(
                    f"图片转 PDF 进行中，请稍等...")

            images_paths = [f for f in input_paths if f.lower().endswith(
                ('.png', '.jpg', '.jpeg', '.bmp'))]
            # images_paths = natsorted(images_paths)

            if not images_paths:
                raise ValueError("没有找到图片文件")

            image_list = []
            for img_path in images_paths:
                # img_path = os.path.join(self.image_folder, image)
                with Image.open(img_path) as img:
                    img = img.convert('RGB')
                    img = self.apply_orientation(img)
                    # 调整图片尺寸
                    # img = self.fit_image_to_page(img)
                    image_list.append(img)

            if image_list:
                image_list[0].save(output_path, save_all=True,
                                   append_images=image_list[1:])
            else:
                if log_callback:
                    log_callback("没有图片可以转换")
                messagebox.showwarning("警告", "没有图片可以转换")
        except Exception as e:
            if log_callback:
                log_callback(f"错误: {str(e)}")
            messagebox.showerror("错误", f"错误: {str(e)}")
        finally:
            cancel_event.clear()

    def run(self, log_callback=None):
        paths = self.image_paths.split(';')
        if paths:
            paths = natsorted(paths)
            file_name_without_ext, _ = os.path.splitext(
                os.path.basename(paths[0]))
            self.convert_images_to_pdf(paths, os.path.join(
                self.pdf_path, file_name_without_ext+'.pdf'), log_callback)

        if log_callback:
            log_callback("转换成功！")

        messagebox.showinfo("完成", "图片转PDF成功！")


class PdfToImagesApp:
    def __init__(self, root):
        self.root = root
        self.root.title("深空PDF转图片工具V1.0")
        self.root.geometry("600x240")
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)

        self.input_path = ""
        self.output_folder = ""
        self.conversion_thread = None
        self.selected_conversion_type = tk.StringVar(value="image")  # 默认选择转图片
        self.readme = "最新：B站/抖音/小红书/视频号 --> CN糖糖"
        self.create_widgets()
        self.bind_drag_and_drop()

    def create_widgets(self):
        # 设置样式
        style = ttk.Style()
        style.configure("TButton", padding=6, relief="flat", background="#ccc")
        style.configure("TLabel", padding=6, background="#fff")
        style.configure("TProgressbar", thickness=10, background="#2196F3")

        # 统一的框架
        self.main_frame = ttk.Frame(self.root)
        self.main_frame.grid(row=0, column=0, sticky="nsew")
        self.main_frame.columnconfigure(0, weight=1)
        self.main_frame.rowconfigure(0, weight=1)
        self.main_frame.rowconfigure(1, weight=1)
        self.main_frame.rowconfigure(2, weight=1)
        self.main_frame.rowconfigure(3, weight=1)

        # 选择输入路径部分
        self.input_frame = ttk.Frame(self.main_frame)
        self.input_frame.grid(row=0, column=0, sticky="ew", padx=20, pady=5)
        self.input_frame.columnconfigure(0, weight=1)

        self.input_entry = ttk.Entry(self.input_frame, width=70)
        self.input_entry.grid(row=0, column=0, sticky="ew", padx=5, pady=5)

        self.input_button = ttk.Button(
            self.input_frame, text="输入...", command=self.select_input_path)
        self.input_button.grid(row=0, column=1, padx=5, pady=5)

        # 选择输出文件夹部分
        self.folder_frame = ttk.Frame(self.main_frame)
        self.folder_frame.grid(row=1, column=0, sticky="ew", padx=20, pady=5)
        self.folder_frame.columnconfigure(0, weight=1)

        self.folder_entry = ttk.Entry(self.folder_frame, width=70)
        self.folder_entry.grid(row=0, column=0, sticky="ew", padx=5, pady=5)

        self.folder_button = ttk.Button(
            self.folder_frame, text="保存...", command=self.select_output_folder)
        self.folder_button.grid(row=0, column=1, padx=5, pady=5)

        # 回显区域
        self.log_text = ttk.Label(
            self.main_frame, text=self.readme)
        self.log_text.grid(row=2, column=0, pady=5)

        # 转换选项部分
        self.conversion_frame = ttk.Frame(self.main_frame)
        self.conversion_frame.grid(row=3, column=0, pady=10)
        self.conversion_frame.columnconfigure(0, weight=1)
        self.conversion_frame.columnconfigure(1, weight=1)
        self.conversion_frame.columnconfigure(2, weight=1)
        self.conversion_frame.columnconfigure(3, weight=1)

        self.image_radio = ttk.Radiobutton(
            self.conversion_frame, text="pdf -> images", variable=self.selected_conversion_type, value="image")
        self.image_radio.grid(row=0, column=1, padx=5, pady=5, sticky="w")

        self.word_radio = ttk.Radiobutton(
            self.conversion_frame, text="pdf -> word", variable=self.selected_conversion_type, value="word")
        self.word_radio.grid(row=0, column=2, padx=5, pady=5, sticky="w")

        self.pdf_radio = ttk.Radiobutton(
            self.conversion_frame, text="images -> pdf", variable=self.selected_conversion_type, value="pdf")
        self.pdf_radio.grid(row=0, column=3, padx=5, pady=5, sticky="w")

        # 执行转换按钮
        self.convert_button = ttk.Button(
            self.conversion_frame, text="Go", command=self.start_conversion)
        self.convert_button.grid(row=1, column=1, columnspan=3, padx=5, pady=5)

    def bind_drag_and_drop(self):
        self.root.drop_target_register(DND_FILES)
        self.root.dnd_bind('<<Drop>>', self.handle_drop)

    def paths_parse(self, paths):
        first_flag = False
        for path in paths:
            if os.path.isfile(path):
                # print(path)
                if not first_flag:
                    dir_name = os.path.dirname(path)
                    self.input_entry.delete(0, tk.END)
                    self.output_folder = dir_name
                    # self.output_folder = os.path.join(dir_name, 'output')
                    self.folder_entry.delete(0, tk.END)
                    self.folder_entry.insert(0, self.output_folder)
                    self.input_path = path
                    first_flag = True
                else:
                    self.input_path = self.input_path + ";"+path
        self.input_entry.insert(0, self.input_path)

    def process_event_data(self, event_data):
        # 去除花括号和单引号
        event_data = event_data.replace('{', '').replace('}', '')
        # 正则表达式匹配路径
        pattern = r'[A-Za-z]:[\\/][^\\/*?:"<>|\r\n]+(?:[\\/][^\\/*?:"<>|\r\n]+)*\.[a-zA-Z0-9]+'

        # 查找所有匹配的路径
        paths = re.findall(pattern, event_data)

        return paths

    def handle_drop(self, event):
        data = event.data
        if data:
            paths = self.process_event_data(data)
            self.paths_parse(paths)

    def select_input_path(self):
        filetypes = [("files", "*.pdf;*.jpg;*.png;*.jpeg"),
                     ("All files", "*.*")]
        paths = filedialog.askopenfilenames(filetypes=filetypes)
        if paths:
            self.paths_parse(paths)

    def select_output_folder(self):
        self.output_folder = filedialog.askdirectory()
        if self.output_folder:
            self.folder_entry.delete(0, tk.END)
            self.folder_entry.insert(0, self.output_folder)

    def ensure_output_folder_exists(self):
        """确保输出文件夹存在"""
        if not os.path.exists(self.output_folder):
            os.makedirs(self.output_folder)

    def start_image_conversion(self):
        if not self.input_path or not self.output_folder:
            messagebox.showwarning("警告", "请先输入文件！")
            return
        self.ensure_output_folder_exists()
        self.convert_button.config(state=tk.DISABLED)
        conversion_thread = threading.Thread(
            target=self.run_image_conversion)
        conversion_thread.start()

    def run_image_conversion(self):
        converter = PdfToImagesConverter(self.input_path, self.output_folder)
        converter.run(None, self.update_log)
        self.convert_button.config(state=tk.NORMAL)

    def start_word_conversion(self):
        if not self.input_path or not self.output_folder:
            messagebox.showwarning("警告", "请先输入文件！")
            return

        self.ensure_output_folder_exists()
        self.convert_button.config(state=tk.DISABLED)
        conversion_thread = threading.Thread(
            target=self.run_word_conversion)
        conversion_thread.start()

    def run_word_conversion(self):
        converter = PdfToWordConverter(self.input_path, self.output_folder)
        converter.run(self.update_log)
        self.convert_button.config(state=tk.NORMAL)

    def start_pdf_conversion(self):
        if not self.input_path or not self.output_folder:
            messagebox.showwarning("警告", "请先输入文件！")
            return
        self.convert_button.config(state=tk.DISABLED)
        self.ensure_output_folder_exists()
        conversion_thread = threading.Thread(
            target=self.run_pdf_conversion)
        conversion_thread.start()

        # if os.path.isdir(self.input_path):
        #     pdf_path = os.path.join(self.output_folder, "output.pdf")
        #     converter = ImagesToPdfConverter(self.input_path, pdf_path)
        #     self.conversion_thread = threading.Thread(
        #         target=converter.convert_images_to_pdf, args=[self.update_log])
        #     self.conversion_thread.start()
        # else:
        #     messagebox.showwarning("警告", "输入路径必须是图片文件夹")

    def run_pdf_conversion(self):
        converter = ImagesToPdfConverter(self.input_path, self.output_folder)
        converter.run(self.update_log)
        self.convert_button.config(state=tk.NORMAL)

    def start_conversion(self):
        conversion_type = self.selected_conversion_type.get()
        if conversion_type == "image":
            self.start_image_conversion()
        elif conversion_type == "word":
            self.start_word_conversion()
        elif conversion_type == "pdf":
            self.start_pdf_conversion()

    def update_log(self, message):
        self.log_text.config(text=message)


if __name__ == "__main__":
    root = TkinterDnD.Tk()
    root.attributes('-topmost', True)
    app = PdfToImagesApp(root)
    root.mainloop()
