{% import "sql_dialects.sql.j2" as sql_templates %}
{# Iterate over classes and generate CREATE TABLE statements #}
{% for class_obj in model.classes_sorted_by_inheritance() %}
    {% set class_name = class_obj.name %}
    {% set attributes = class_obj.attributes %}
    {{- sql_templates.create_table(class_name, attributes, types, sql_dialect) }}
    {# Handling generalizations (inheritance) #}
    {% if class_obj.generalizations %}
        {% for generalization in class_obj.generalizations %}
            {% if generalization.specific.name == class_name %}
                {{- sql_templates.add_generalization(class_name, generalization, sql_dialect) }}
            {% endif %}
        {% endfor %}
    {% endif %}
{% endfor %}
{# Iterate over associations and generate SQL statements based on association type #}
{% for association in model.associations %}
    {% if association.ends|length == 2 -%}
        {% set ns = namespace(end1=None, end2=None) %}
        {% for end in association.ends %}
            {% set ns.end1=end if loop.index == 1 else ns.end1 %}
            {% set ns.end2=end if loop.index == 2 else ns.end2 %}
        {% endfor %}
        {% set class1_name = ns.end1.type.name %}
        {% set class2_name = ns.end2.type.name %}
        {# Check multiplicity and generate appropriate SQL statement #}
        {% if ns.end1.multiplicity.max > 1 and ns.end2.multiplicity.max > 1 %}
        {# N:M Relationship: Create intermediate table #}
            {{- sql_templates.create_nm_table(class1_name, class2_name, sql_dialect) }}
        {% elif ns.end1.multiplicity.max > 1 and ns.end2.multiplicity.max == 1 %}
        {# N:1 Relationship: Add reference to Nary end #}
            {{- sql_templates.alter_table(class1_name, class2_name, class2_name, class2_name, sql_dialect) }}
        {% elif ns.end1.multiplicity.max == 1 and ns.end2.multiplicity.max > 1 %}
        {# 1:N Relationship: Add reference to Nary end #}
            {{- sql_templates.alter_table(class2_name, class1_name, class1_name, class1_name, sql_dialect) }}
        {% elif ns.end1.multiplicity.max == 1 and ns.end2.multiplicity.max == 1 %}
        {# 1:1 Relationship: Add unique reference to one of the ends #}
            {{- sql_templates.alter_table(class1_name, class2_name, class2_name, class2_name, sql_dialect) }}
        {% endif %}
    {% else %}
    {# Convert Nary relationship to Binary relationships and intermediate table #}
        {% set intermediate_class = association.name %}
        {{- sql_templates.create_table(intermediate_class, [], types, sql_dialect) }}
        {% set end_intermediate_multiplicity_max = 9999 %}
        {% for end in association.ends %}
            {# Check multiplicity and generate appropriate SQL statement #}
            {% set class1_name = intermediate_class %}
            {% set class2_name = end.type.name %}
            {# End of intermediate table should have multiplicity of the original end to the class #}
            {% if end.multiplicity.max > 1 and end_intermediate_multiplicity_max > 1 %}
            {# N:M Relationship: Create intermediate table #}
                {{- sql_templates.create_nm_table(class1_name, class2_name, sql_dialect) }}
            {% elif end.multiplicity.max == 1 and end_intermediate_multiplicity_max > 1 %}
                {# 1:N Relationship: Add reference to Nary end #}
                {{- sql_templates.alter_table(class1_name, class2_name, class2_name, class2_name, sql_dialect) }}
            {% endif %}
        {% endfor %}
    {% endif %}
{%- endfor %}