#  Copyright (c) 2025  Jeffrey Hsu - JITToolBox
#  #
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  #
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  #
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.

import math
import os
import traceback
from typing import Literal

import pythoncom
from PySide6.QtCore import QObject, Signal
from win32com import client

from module.achievement.doc import DocxWriter
from module.achievement.excel import ExcelReader
from module.defense.doc import DocPaper
from module.schema import Course, Student, Question
from utils.function import resource_path


class DTGWorker(QObject):
    progress = Signal((int,), (str,))
    finished = Signal()
    error = Signal(str, str)

    def __init__(
            self,
            input_student_filepath: str,
            input_question_filepath: str,
            output_filepath: str,
            output_filename: str,
            output_type: Literal['pdf', 'word'] = 'pdf'
    ):
        super().__init__()
        self.input_filepath = input_student_filepath
        self.input_question_filepath = input_question_filepath
        self.output_filepath = output_filepath
        self.output_filename = output_filename
        self.output_type = output_type

    def run(self):
        try:
            course = Course.load_from_xls(self.input_filepath)
            students = Student.load_from_xls(self.input_filepath)
            questions = Question.load_from_xls(self.input_question_filepath)

            max_question_count = math.ceil(len(students) * 3 / len(questions))

            d = DocPaper(self.output_filename, resource_path("template/template-defense-paper-paper.docx"))
            for index, student in enumerate(students):
                if (p := int((index + 1) / len(students) * 100)) != 100:
                    self.progress[int].emit(p)
                student.pick_question(questions, max_count=max_question_count)
                d.add_paper(course, student)
            d.save(self.output_filepath)

            word_file = self.output_filepath + "/" + self.output_filename + ".docx"
            pdf_file = self.output_filepath + "/" + self.output_filename + ".pdf"

            if self.output_type == 'pdf':
                self.progress[int].emit(101)
                self.progress[str].emit("正在转换文件")

                if os.path.exists(pdf_file):
                    os.remove(pdf_file)
                pythoncom.CoInitialize()
                # https://stackoverflow.com/questions/71292585/python-docx2pdf-attributeerror-open-saveas
                word = client.Dispatch("Word.Application")
                doc = word.Documents.Open(word_file)
                try:
                    doc.SaveAs(pdf_file, 17)
                    doc.Close()
                    os.remove(word_file)
                    os.startfile(pdf_file)
                except Exception as e:
                    doc.Close()
                    os.startfile(word_file)
                    raise Exception("PDF转换失败，但Word文档已生成，已打开Word文档") from e
                finally:
                    word.Quit()
            elif self.output_type == 'word':
                os.startfile(word_file)
        except Exception:
            self.error.emit("😢 不好出错了", traceback.format_exc())
            self.progress[int].emit(-1)
        finally:
            self.finished.emit()


class ARGWorker(QObject):
    finished = Signal()
    error = Signal(str, str)
    info = Signal(str, str)

    def __init__(self, input_filepath: str, output_filepath: str, output_filename: str, disable_cc: bool = False):
        super().__init__()
        self.input_filepath = input_filepath
        self.output_filepath = output_filepath
        self.output_filename = output_filename
        self.disable_compatibility_check = disable_cc

    def run(self):
        try:
            excel = ExcelReader(self.input_filepath, self.disable_compatibility_check, self.info.emit)
            excel.run()

            doc = DocxWriter(self.output_filepath, self.output_filename, excel, self.info.emit)
            doc.write()
        except Exception as e:
            self.error.emit("😢 不好出错了", str(e))
        finally:
            self.finished.emit()
