import random
from math import gcd
import xml.etree.ElementTree as ET

def lcm(a, b):
    """Berechnet das kleinste gemeinsame Vielfache."""
    return abs(a * b) // gcd(a, b)

def create_formula_question(numerator1, denominator1, numerator2, denominator2, n):
    """Erzeugt eine Frage im Format 'Formulas'."""
    # GCD und das kleinste gemeinsame Vielfache für die Denominator
    common_denominator = lcm(denominator1, denominator2)
    new_numerator = (numerator1 * (common_denominator // denominator1)) + (numerator2 * (common_denominator // denominator2))
    gcd_result = gcd(new_numerator, common_denominator)
    if gcd_result > 1:
        print("kürzbar")
        shortable = True
        shortened_numerator = new_numerator // gcd_result
        shortened_denominator = common_denominator // gcd_result
    else:
        shortable = False

    question = ET.Element('question', attrib={'type': 'formulas'})

    name_elem = ET.SubElement(question, 'name')
    text_elem = ET.SubElement(name_elem, 'text')
    text_elem.text = 'Addition von 2 ungleichnamigen Brüchen {} E'.format(n)

    questiontext_elem = ET.SubElement(question, 'questiontext', attrib={'format': 'html'})
    text_elem = ET.SubElement(questiontext_elem, 'text')
    if shortable:
        text_elem.text = '''<![CDATA[ <p>Addiere die Brüche und kürze das Ergebnis so weit wie möglich.</p>
                            <p>{#A} </p> ]]> '''
    else:
        text_elem.text = '''<![CDATA[ <p>Addiere die beiden Brüche.</p>
                            <p>{#A} </p> ]]> '''

    # Allgemeines Feedback
    generalfeedback_elem = ET.SubElement(question, 'generalfeedback', attrib={'format': 'html'})
    text_elem = ET.SubElement(generalfeedback_elem, 'text')
    text_elem.text = ' '

    # Grundlegende Bewertungsinformationen
    ET.SubElement(question, 'defaultgrade').text = '1.0000000'
    ET.SubElement(question, 'penalty').text = '0.3333333'
    ET.SubElement(question, 'hidden').text = '0'
    ET.SubElement(question, 'idnumber').text = ' '

    # Feedback für korrekte und inkorrekte Antworten
    correctfeedback_elem = ET.SubElement(question, 'correctfeedback', attrib={'format': 'html'})
    text_elem = ET.SubElement(correctfeedback_elem, 'text')
    text_elem.text = '''<![CDATA[ <p>Die Antwort ist richtig.</p> ]]> '''

    partiallycorrectfeedback_elem = ET.SubElement(question, 'partiallycorrectfeedback', attrib={'format': 'html'})
    text_elem = ET.SubElement(partiallycorrectfeedback_elem, 'text')
    text_elem.text = '''<![CDATA[ <p>Die Antwort ist teilweise richtig.</p> ]]> '''

    incorrectfeedback_elem = ET.SubElement(question, 'incorrectfeedback', attrib={'format': 'html'})
    text_elem = ET.SubElement(incorrectfeedback_elem, 'text')
    text_elem.text = '''<![CDATA[ <p>Die Antwort ist falsch.</p> ]]>'''

    ET.SubElement(question, 'shownumcorrect')

    varsrandom_elem = ET.SubElement(question, 'varsrandom')
    text_elem = ET.SubElement(varsrandom_elem, 'text')
    text_elem.text = f' '

    # Globale Variablen definieren
    varsglobal_elem = ET.SubElement(question, 'varsglobal')
    text_elem = ET.SubElement(varsglobal_elem, 'text')
    text_elem.text = f'n = [{numerator1}, {numerator2}];\n d = [{denominator1}, {denominator2}];'

    answernumbering_elem = ET.SubElement(question, 'answernumbering')
    text_elem = ET.SubElement(answernumbering_elem, 'text')
    text_elem.text = 'ABCD'

    # Antworten definieren
    answers_elem = ET.SubElement(question, 'answers')

    # Indizes für die Antworten
    partindex_elem = ET.SubElement(answers_elem, 'partindex')
    ET.SubElement(partindex_elem, 'text').text = '0'

    placeholder_elem = ET.SubElement(answers_elem, 'placeholder')
    ET.SubElement(placeholder_elem, 'text').text = '#A'

    # Punktzahl auf Teilaufgabe
    answermark_elem = ET.SubElement(answers_elem, 'answermark')
    if shortable:
        ET.SubElement(answermark_elem, 'text').text = '2'
    else:
        ET.SubElement(answermark_elem, 'text').text = '1'

    answertype_elem = ET.SubElement(answers_elem, 'answertype')
    ET.SubElement(answertype_elem, 'text').text = '0'

    numbox_elem = ET.SubElement(answers_elem, 'numbox')
    ET.SubElement(numbox_elem, 'text').text = '2'

    # Berechnungsvariablen
    vars1_elem = ET.SubElement(answers_elem, 'vars1')
    if shortable:
        vars1_elem_text = "<![CDATA[ g = gcd(d[0],d[1]);\n cd =  abs(d[0] * d[1]) / g;\n e = [cd / d[0], cd / d[1]];\n nums = [n[0]*e[0], n[1]*e[1]];\n thesumnum = nums[0] + nums[1];\n gcdres = gcd(thesumnum,cd);\n snum = thesumnum / gcdres;\n sdenom = cd / gcdres;]]>"
    else:
        vars1_elem_text = "<![CDATA[ g = gcd(d[0],d[1]);\ncd = abs(d[0] * d[1]) / g;\ne = [cd / d[0], cd / d[1]];\nnums = [n[0]*e[0], n[1]*e[1]];\nthesumnum = nums[0] + nums[1];]]>"
    ET.SubElement(vars1_elem, 'text').text = vars1_elem_text

    # Antwort
    answer_elem = ET.SubElement(answers_elem, 'answer')
    if shortable:
        answer_text = '[thesumnum, cd, snum, sdenom]'
    else:
        answer_text = '[thesumnum, cd]'
    ET.SubElement(answer_elem, 'text').text = answer_text

    answernotunique_elem = ET.SubElement(answers_elem, 'answernotunique')
    ET.SubElement(answernotunique_elem, 'text').text = '0'

    vars2_elem = ET.SubElement(answers_elem, 'vars2')
    if shortable:
        vars2_elem_text = "<![CDATA[ ga = _0 == thesumnum && _1 == cd;\n gb = (_0 / _1) == (thesumnum / cd);\n gsa = _2 == snum && _3 == sdenom;\n gsb = (_2 / _3) == (snum / sdenom); ]]>"
    else:
        vars2_elem_text = "<![CDATA[ ga = _0 == thesumnum && _1 == cd; gb = (_0 / _1) == (thesumnum / cd); ]]>"
    ET.SubElement(vars2_elem, 'text').text = vars2_elem_text

    correctness_elem = ET.SubElement(answers_elem, 'correctness')
    if shortable:
        ET.SubElement(correctness_elem, 'text').text = '0.25*ga + 0.25*gb + 0.25*gsa + 0.25*gsb'
    else:
        ET.SubElement(correctness_elem, 'text').text = '0.5*ga + 0.5*gb'

    unitpenalty_elem = ET.SubElement(answers_elem, 'unitpenalty')
    ET.SubElement(unitpenalty_elem, 'text').text = '1'

    postunit_elem = ET.SubElement(answers_elem, 'postunit')
    ET.SubElement(postunit_elem, 'text').text = ' '

    ruleid_elem = ET.SubElement(answers_elem, 'ruleid')
    ET.SubElement(ruleid_elem, 'text').text = '1'

    otherrule_elem = ET.SubElement(answers_elem, 'otherrule')
    ET.SubElement(otherrule_elem, 'text').text = ' '

    # Unterfragen-Text
    subqtext_elem = ET.SubElement(answers_elem, 'subqtext', attrib={'format': 'html'})
    if shortable:
        sub_question_text = '''<![CDATA[ <p>Berechne:</p> <p>\\(\\Large \\displaystyle \\frac{{n[0]}}{{d[0]}} + \\frac{{n[1]}}{{d[1]}} =\\) {_0} / {_1} = gekürzt: {_2} / {_3}</p> ]]> '''
    else:
        sub_question_text = '''<![CDATA[ <p>Berechne:</p> <p>\\(\\Large \\displaystyle \\frac{{n[0]}}{{d[0]}} + \\frac{{n[1]}}{{d[1]}} =\\) {_0} / {_1}</p> ]]> '''
    ET.SubElement(subqtext_elem, 'text').text = sub_question_text

    # Lösungshinweis
    feedback_elem = ET.SubElement(answers_elem, 'feedback', attrib={'format': 'html'})
    if shortable:
        feedback_text = '''<![CDATA[ <h4>Lösungshinweis</h4>
                           <p>Die korrekte Lösung ist:</p>
                           <p>\\(\\Large \\displaystyle \\frac{{n[0]}}{{d[0]}} + \\frac{{n[1]}}{{d[1]}} = \\frac{{nums[0]}}{{cd}} + \\frac{{nums[1]}}{{cd}} = \\frac{{thesumnum}}{{cd}} = \\frac{{snum}}{{sdenom}} \\) </p> ]]>'''
    else:
        feedback_text = '''<![CDATA[ <h4>Lösungshinweis</h4>
                           <p>Die korrekte Lösung ist:</p>
                           <p>\\(\\Large \\displaystyle \\frac{{n[0]}}{{d[0]}} + \\frac{{n[1]}}{{d[1]}} = \\frac{{nums[0]}}{{cd}} + \\frac{{nums[1]}}{{cd}} = \\frac{{thesumnum}}{{cd}} \\) </p> ]]>'''
    ET.SubElement(feedback_elem, 'text').text = feedback_text

    # correctfeedback

    correctfeedback_elem = ET.SubElement(answers_elem, 'correctfeedback', attrib={'format': 'html'})
    correctfeedback_text = '''<![CDATA[ <p>Richtig!</p>]]>'''
    ET.SubElement(correctfeedback_elem, 'text').text = correctfeedback_text

    # partially correct feedback

    pcorrectfeedback_elem = ET.SubElement(answers_elem, 'partiallycorrectfeedback', attrib={'format': 'html'})
    pcorrectfeedback_text = '''<![CDATA[ <p>Teilweise richtig.</p>]]>'''
    ET.SubElement(pcorrectfeedback_elem, 'text').text = pcorrectfeedback_text

    # incorrect feedback
    incorrectfeedback_elem = ET.SubElement(answers_elem, 'incorrectfeedback', attrib={'format': 'html'})
    incorrectfeedback_text = '''<![CDATA[ <p>Leider nicht richtig.</p>]]>'''
    ET.SubElement(incorrectfeedback_elem, 'text').text = incorrectfeedback_text

    return question

def generate_questions(num_questions):
    """Generiert Aufgaben für die Addition ungleichnamiger Brüche."""
    questions = []

    for i in range(num_questions):
        numerator1 = random.randint(1, 10)
        denominator1 = random.randint(2, 10)
        numerator2 = random.randint(1, 10)
        denominator2 = random.randint(2, 10)

        # Sicherstellen, dass die Nenner unterschiedlich sind
        while denominator1 == denominator2:
            denominator2 = random.randint(2, 10)

        question = create_formula_question(numerator1, denominator1, numerator2, denominator2, i)
        questions.append(question)

    return questions

def create_quiz(questions):
    """Erzeugt die gesamte Quiz-Struktur."""
    quiz = ET.Element('quiz')
    for q in questions:
        quiz.append(q)
    return quiz

def save_to_file(xml_element, filename):
    """Speichert das XML-Dokument in einer Datei."""
    tree = ET.ElementTree(xml_element)
    ET.indent(tree)
    with open(filename, 'wb') as f:
        tree.write(f, encoding='utf-8', xml_declaration=True)

def ersetze_vars2(xml_file):
    # XML-Datei lesen
    with open(xml_file, 'r') as f:
        text = f.read()

    text = text.replace("&amp;","&")
    text = text.replace("&lt;","<")
    text = text.replace("&gt;",">")

    with open(xml_file, 'w') as f:
        f.write(text)


# Hauptprogramm
if __name__ == "__main__":
    num_questions = 20  # Anzahl der zu generierenden Aufgaben
    questions = generate_questions(num_questions)
    quiz = create_quiz(questions)

    save_to_file(quiz, 'formulas_fraction_addition_quiz.xml')
    ersetze_vars2('formulas_fraction_addition_quiz.xml')

    print("Moodle-XML-Datei 'formulas_fraction_addition_quiz.xml' erfolgreich erstellt.")