#  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 random
from typing import Optional, Tuple, NoReturn

from openpyxl.reader.excel import load_workbook


class Question:
    def __init__(self, no: str, topic: str):
        self._no: str = no
        self._topic: str = topic
        self._count: int = 0

    def __str__(self):
        return f"Question<No: {self._no}, Topic: {self._topic}>"

    def __repr__(self):
        return self.__str__()

    @staticmethod
    def load_from_csv(path: Optional[str] = None) -> list['Question']:
        questions = []
        with open(path if path else '../files/questions.csv', encoding='gbk') as f:
            for line in f.readlines():
                questions.append(Question(*line.strip('\n').split(',')))
        return questions

    @staticmethod
    def load_from_xls(path: str) -> list['Question']:
        questions = []
        wb = load_workbook(path, read_only=True)
        ws = wb.active
        for row in ws.iter_rows(min_col=2, max_col=3, min_row=2, values_only=True):
            if row[0] is None and row[1] is None:
                break
            questions.append(Question(*row))
        wb.close()
        return questions

    @property
    def no(self) -> str:
        return self._no

    @property
    def topic(self) -> str:
        return self._topic

    def increase_count(self) -> None:
        self._count += 1

    def can_pick(self, max_count: int) -> bool:
        return self._count <= max_count


class Student:
    def __init__(self, no: str, so: str, name: str, major: str, class_name: str):
        self._no: str = no
        self._so: str = so
        self._name: str = name
        self._major: str = major
        self._class_name: str = class_name
        self._picked_questions: list[Question] = []

    def __str__(self):
        return f"Student<No: {self._no}, SO: {self._so}, Name: {self._name}, Major: {self._major}, Class: {self._class_name}>"

    def __repr__(self):
        return self.__str__()

    @staticmethod
    def load_from_xls(path: str) -> list['Student'] | NoReturn:
        wb = load_workbook(path, read_only=True)
        ws = wb.active
        students = []

        if ws.title == 'Sheet1':
            for row in ws.iter_rows(min_row=6, max_col=5, values_only=True):
                students.append(Student(*row))
        elif ws.title == '初始录入':
            for row in ws.iter_rows(min_row=13, max_col=5, values_only=True):
                students.append(Student(*row))
        else:
            raise Exception("无法解析学生名单")

        wb.close()
        return [x for x in students if x.valid]

    @property
    def valid(self) -> bool:
        return bool(self._no and self._so and self._name and self._major and self._class_name)

    @property
    def picked_questions(self) -> list[Question]:
        return self._picked_questions

    @property
    def no(self) -> str:
        return self._no

    @property
    def so(self) -> str:
        return self._so

    @property
    def name(self) -> str:
        return self._name

    @property
    def major(self) -> str:
        return self._major

    @property
    def class_name(self) -> str:
        return self._class_name

    def pick_question(self, questions: list[Question], num: int = 3, max_count: int = 3) -> None:
        available_questions = [q for q in questions if q.can_pick(max_count)]

        if len(available_questions) < num:
            raise ValueError("Not enough questions with count <= max_count")
        self._picked_questions = random.sample(available_questions, num)

        for q in self._picked_questions:
            q.increase_count()


class Course:
    def __init__(self, name: str):
        self._name = name

    def __str__(self):
        return f"Course<Name: {self._name}>"

    def __repr__(self):
        return self.__str__()

    @staticmethod
    def load_from_xls(path: str) -> 'Course' | NoReturn:
        wb = load_workbook(path, read_only=True)
        ws = wb.active
        if ws.title == 'Sheet1':
            name: str = ws['E3'].value[5:]
        elif ws.title == '初始录入':
            name: str = ws['D5'].value
        else:
            raise Exception("无法解析课程名")
        wb.close()
        return Course(name)

    @property
    def name(self) -> str:
        return self._name


class Performance:
    def __init__(self, scores: Tuple[float, float, float], rates: Tuple[float, float, float], achievement: float):
        self.scores = scores  # (平时平均分, 大作业平均分, 试卷平均分)
        self.rates = rates  # (平时得分率, 大作业得分率, 试卷得分率)
        self.achievement = achievement  # 达成度

    def __str__(self):
        return f"Performance(scores={self.scores}, rates={self.rates}, achievement={self.achievement})"


if __name__ == '__main__':
    ...
