import re

import requests


# a minimalistic moodle api wrapper, just for the purpose of this project
# it's not meant to be complete
# it's not meant to be efficient
# it's not meant to be pythonic
# it's not meant to be a good moodle api wrapper


class Category:
    def __init__(self, id_i: int, name: str, courses: list):
        self.id = id_i
        self.name = name
        self.courses = courses


class Course:
    def __init__(self, id_i: int, shortname: str, fullname: str, enrolled_user_count: int):
        self.shortname = shortname
        self.fullname = fullname
        self.id = id_i
        self.enrolled_user_count = enrolled_user_count


class Section:
    def __init__(self, id_i: int, name: str, htmlcontent: str, modules: list):
        self.id = id_i
        self.autoName = False
        if len(re.sub(r'\W+', '', name)) == 0:
            name = "Section " + str(id_i)
            self.autoName = True
        self.name = name
        self.htmlcontent = htmlcontent
        self.modules = modules


class Label:
    def __init__(self, id_i: int, htmlcontent: str):
        self.id = id_i
        self.htmlcontent = htmlcontent
        self.name = "Label" + str(id_i)


class Url:
    def __init__(self, id_i: int, name: str, description: str, url: str):
        self.id = id_i
        self.name = name
        self.description = description
        self.url = url


class MoodleUser:
    def __init__(self, username: str, fullname: str, user_picture_url: str):
        self.username = username
        self.fullname = fullname
        self.user_picture_url = user_picture_url


class Folder:
    def __init__(self, id_i: int, name: str, files: list):
        self.id = id_i
        self.name = name
        self.files = files


class File:
    def __init__(self, filename: str, filesize: int, fileurl: str, file_relative_path: str | None, created: int | None,
                 modified: int | None):
        self.filename = filename
        self.name = filename
        self.filesize = filesize
        self.fileurl = fileurl
        self.file_relative_path = file_relative_path
        self.created = created
        self.modified = modified


class Moodle:
    def __init__(self, site_url, username, password):
        self.user_id = None
        self.token = None
        self.private_token = None
        self.site_url = site_url
        self.username = username
        self.password = password
        self.site_name = None
        self.release = None
        self.lang = None

    def login(self) -> None:
        url = self.site_url + "/login/token.php?username=" + self.username + "&password=" + self.password + "&service=moodle_mobile_app"
        response = requests.post(url)
        r = response.json()
        if "error" in r.keys():
            raise Exception(r["error"])
        self.token = r["token"]
        self.private_token = r["privatetoken"]
        self.get_user()

    def get_user(self) -> MoodleUser:
        url = self.site_url + "/webservice/rest/server.php?moodlewsrestformat=json"
        re = requests.post(url, data={"wstoken": self.token, "wsfunction": "core_webservice_get_site_info"})
        r = re.json()
        self.user_id = r["userid"]
        self.userpictureurl = r["userpictureurl"]
        self.fullname = r["fullname"]
        self.site_name = r["sitename"]
        self.release = r["release"]
        self.lang = r["lang"]
        return MoodleUser(self.username, self.fullname, self.userpictureurl)

    def get_enrolled_categories(self) -> list[Category]:
        url = self.site_url + "/webservice/rest/server.php?moodlewsrestformat=json"
        re = requests.post(url, data={"wstoken": self.token, "wsfunction": "core_enrol_get_users_courses",
                                      "userid": self.user_id})
        r = re.json()
        categories = {}
        for course in r:
            if course["category"] not in categories.keys():
                categories[course["category"]] = []
            categories[course["category"]].append(
                Course(course["id"], course["shortname"], course["fullname"], course["enrolledusercount"]))
        lret = []
        for category_id in categories.keys():
            c = self.get_category_by_id(category_id)
            c.courses = categories[category_id]
            lret.append(c)
        return lret

    def get_enrolled_courses(self) -> Category:
        url = self.site_url + "/webservice/rest/server.php?moodlewsrestformat=json"
        re = requests.post(url, data={"wstoken": self.token, "wsfunction": "core_enrol_get_users_courses",
                                      "userid": self.user_id})
        return re.json()

    def get_category_by_id(self, category_id: int) -> Category:
        url = self.site_url + "/webservice/rest/server.php?moodlewsrestformat=json"
        re = requests.post(url, data={"wstoken": self.token, "wsfunction": "core_course_get_categories",
                                      "criteria[0][key]": "id", "criteria[0][value]": category_id})
        r = re.json()
        return Category(r[0]["id"], r[0]["name"], [])

    def get_course_content(self, course_id: int) -> list[Section]:
        url = self.site_url + "/webservice/rest/server.php?moodlewsrestformat=json"
        re = requests.post(url, data={"wstoken": self.token, "wsfunction": "core_course_get_contents",
                                      "courseid": course_id})
        r = re.json()
        sections = []
        for section in r:
            modules = []
            for module in section["modules"]:
                if module["modname"] == "label":
                    modules.append(Label(module["id"], module["description"]))
                elif module["modname"] == "url":
                    modules.append(Url(module["id"], module["name"],
                                       (module["description"] if "description" in module.keys() else ""),
                                       module["url"]))
                elif module["modname"] == "folder" or module["modname"] == "resource":
                    modules.append(self.__folder_rec_exploder(module))
                elif module["modname"] == "file":
                    modules.append(File(module["filename"], module["filesize"], module["fileurl"], module["filepath"], module["timecreated"], module["timemodified"]))

            sections.append(Section(section["id"], section["name"], section["summary"], modules))
        return sections

    def __folder_rec_exploder(self, folder_module: dict) -> Folder:
        f = Folder(folder_module["id"], folder_module["name"], [])
        for file in folder_module["contents"]:
            if file["type"] == "file":
                f.files.append(File(file["filename"], file["filesize"], file["fileurl"], file["filepath"], file["timecreated"], file["timemodified"]))
            else:
                f.files.append(self.__folder_rec_exploder(file))
        return f
