#!/usr/bin/env python
from __future__ import annotations

from typing import TYPE_CHECKING

from logprise import logger

from smartschool import PathCredentials, Results, Smartschool, SmartSchoolDownloadError
from smartschool.common import IsSaved, save, send_email

if TYPE_CHECKING:
    from smartschool.objects import ResultWithoutDetails


def is_punten_json_the_same(previous: ResultWithoutDetails, current: ResultWithoutDetails) -> bool:
    if previous == current:  # No need to dig into it...
        return True

    check_keys_for_equality = [
        "identifier",
        "graphic/type",
        "graphic/color",
        "graphic/value",
        "graphic/description",
        "courses/0/name",
        "courses/0/teachers/0/name/startingWithFirstName",
        "feedback/0/user/name/startingWithFirstName",
        "feedback/0/text",
        "feedback/1/user/name/startingWithFirstName",
        "feedback/1/text",
        "feedback/2/user/name/startingWithFirstName",
        "feedback/2/text",
        "feedback/3/user/name/startingWithFirstName",
        "feedback/3/text",
        "feedback/4/user/name/startingWithFirstName",
        "feedback/4/text",
        "feedback/5/user/name/startingWithFirstName",
        "feedback/5/text",
    ]

    def _grab_sub(d: ResultWithoutDetails | dict, k: list[str]) -> dict | list | str | None:
        if not k or d is None:
            return d

        obj = d
        for piece in k:
            if piece.isnumeric():
                piece = int(piece)
                if piece >= len(obj):  # Not enough inside this array >> Assume it's an empty string
                    return ""

                obj = obj[piece]
            else:
                obj = getattr(obj, piece)

        return obj

    try:
        for key in check_keys_for_equality:
            prev = _grab_sub(previous, key.split("/"))
            curr = _grab_sub(current, key.split("/"))

            if prev != curr:
                return False
    except Exception as ex:
        logger.error("Current: ", current)
        logger.error("Previous: ", previous)
        logger.exception(ex)
        raise

    return True


def build_text(
    is_update: bool,  # noqa: FBT001
    result: ResultWithoutDetails,
) -> tuple[str, str]:
    course_name = result.courses[0].name
    teacher_names = [teacher.name.startingWithFirstName for teacher in result.courses[0].teachers]
    test_name = result.name

    achieved = f"{result.graphic.achieved_points:.2f}".rstrip("0").rstrip(".")
    total = f"{result.graphic.total_points:.2f}".rstrip("0").rstrip(".")
    pct = f"{100 * result.graphic.percentage:.2f}".rstrip("0").rstrip(".")

    my_points = f"{achieved}/{total} ({pct}%)"

    text = f"Course: {course_name}\nTest: {test_name}\n\nPoints: {my_points}\n\n"
    for teacher_name in teacher_names:
        text += f"Teacher: {teacher_name}\n"
    text += "\n"

    if result.feedback:
        text += "Feedback:\n"
        for fb in result.feedback:
            text += f"{fb.user.name.startingWithFirstName}: {fb.text}\n"

    if is_update:
        email_subject = "UPDATE: "
    else:
        email_subject = "NEW: "

    email_subject += f"{course_name} - {test_name} - {my_points}"

    limits = {
        1.0: "🥈",
        0.9: "👍",
        0.7: "✔",
        0.5: "🌫",
    }

    icon = "😡"
    for min_pct, symbol in limits.items():
        if result.graphic.percentage >= min_pct:
            icon = symbol
            break

    email_subject = f"{icon} {email_subject}"

    return text, email_subject


def process_result(session: Smartschool, result: ResultWithoutDetails) -> None:
    assert len(result.courses) == 1, f"Multiple courses? {result.courses}"

    logger.info("[{}] Processing '{}'", result.courses[0].name, result.name)

    course_name = result.courses[0].name  # FE: 'Frans'
    id_ = result.identifier

    status = save(session, "punten", course_name, id_, result, is_punten_json_the_same)

    if status == IsSaved.SAME:
        logger.debug(" => Already processed")
        return

    text, subject = build_text(result=result, is_update=status != IsSaved.NEW)
    send_email(subject=subject, text=text, email_from=session.creds.other_info["email_from"], email_to=session.creds.other_info["email_to"])


def main():
    try:
        session = Smartschool(PathCredentials())
        assert "email_from" in session.creds.other_info
        assert "email_to" in session.creds.other_info

        for result in Results(session):
            process_result(session, result)
    except SmartSchoolDownloadError:
        ...


if __name__ == "__main__":
    main()
