{%- set name = metadata.model.name -%}
{%- set s_name = metadata.model.snake_name -%}
{%- set base_schema = metadata.model.base_schema_name -%}
{%- set router = s_name + "_router" -%}
{%- set just_one_pk = metadata.model.pk|length == 1 -%}
{%- set pk_type = (metadata.model.pk.values()|list)[0].python_type_str -%}

from typing import List, Optional
from fastapi import Depends, HTTPException, status
from fastapi_pagination import Page
from fastapi_pagination.ext.sqlalchemy import paginate
import uuid
import datetime
from ..db import get_db, get_async_session
from ..models import *
from ..schemas import *
from ..auth import get_user_db, get_user_manager

{% if not metadata.model.is_user %}
# ------------------------Query Routes------------------------
{% for route in metadata.query_routes() %}
{%- set schema = base_schema + route.schema_suffix -%}
{% if route.is_all %}
def {{ route.name }}(db=Depends(get_db)) -> Page[{{ schema }}]:
    return paginate(db.query({{ name }}))
{% elif just_one_pk %}
def {{ route.name }}(ident: {{ pk_type }}, db=Depends(get_db)) -> {{ schema }}:
    return db.get({{ name }}, ident)
{% endif %}
{% endfor %}
# ---------------------User Query Routes----------------------
from ..auth import current_user
{% for route in metadata.user_query_routes() %}
{% set schema = base_schema + route.schema_suffix %}
def {{ route.name }}(user=Depends(current_user), db=Depends(get_db)) -> Page[{{ schema }}]:
    return paginate(db.query({{ name }}).where({{ name }}.relation_many_user.contains(user)))
{% endfor %}
# -----------------------Create Routes------------------------
{% for route in metadata.create_routes() %}
def {{ route.name }}(
    {%- for field_name, field in metadata.model.fields.items() %}
    {{ field_name }}: {{ field.python_type_str }},
    {%- endfor -%}
    db=Depends(get_db)
    ) -> {{ base_schema }}:
    model = {}
    {%- for field_name in metadata.model.fields.keys() %}
    if {{ field_name }} is not None:
        model["{{ field_name }}"] = {{ field_name }}
    {% endfor -%}
    model = {{ base_schema }}(**model)
    model = {{ name }}(**model.model_dump())
    db.add(model)
    db.commit()
    db.refresh(model)
    return model
{% endfor %}
# -----------------------Update Routes------------------------
{% if just_one_pk %}
{% for route in metadata.update_routes() %}
def {{ route.name }}(ident: {{ pk_type }},
        {%- for field_name, field in metadata.model.fields.items() -%}
        {{field_name}}: Optional[{{field.python_type_str}}] = None,
        {% endfor -%}
        db=Depends(get_db)) -> {{ base_schema }}:
    model = db.get({{ name }}, ident)
    {%- for field_name, field in metadata.model.fields.items() %}
    if {{field_name}} is not None:
        model.{{field_name}} = {{field_name}}
    {% endfor -%}
    db.commit()
    db.refresh(model)
    return model
{% endfor %}
{% endif %}
# -----------------------Delete Routes------------------------
{% for route in metadata.delete_routes() %}
{% if route.is_all %}
def {{ route.name }}(db=Depends(get_db)):
    db.query({{ name }}).delete()
    db.commit()
    return {"message": "deleted"}
{% elif just_one_pk %}
def {{ route.name }}(ident: {{ pk_type }}, db=Depends(get_db)):
    db.delete({{ name }}, ident)
    db.commit()
    return {"message": "deleted"}
{% endif %}
{% endfor %}
{% else %}
async def create_user(email: str, password: str, is_superuser: bool = False):
    import contextlib
    from fastapi_users.exceptions import UserAlreadyExists
    get_async_session_context = contextlib.asynccontextmanager(get_async_session)
    get_user_db_context = contextlib.asynccontextmanager(get_user_db)
    get_user_manager_context = contextlib.asynccontextmanager(get_user_manager)
    async with get_async_session_context() as session:
        async with get_user_db_context(session) as user_db:
            async with get_user_manager_context(user_db) as user_manager:
                user = await user_manager.create(
                    UserCreate(
                        email=email, password=password, is_superuser=is_superuser
                    )
                )
                return user
{% endif %}
# ----------------------Relation Routes-----------------------
{% if just_one_pk %}
{% for route in metadata.relation_routes() %}
{%- set target = route.relation.target -%}
{%- set target_pk_type = (target.pk.values()|list)[0].python_type_str -%}
def {{ route.name }}(ident: {{ pk_type }}, {{ target.snake_name }}_ident: {{ target_pk_type }},
    {%- if not route.is_delete -%}
    {%- for field_name, field in route.relation.link_fields.items() %}
    {{ field_name }}: {{ field.python_type_str }},
    {%- endfor -%}
    {%- endif -%}
    db=Depends(get_db)) -> {{ base_schema }}:
    self: {{ name }} = db.get({{ name }}, ident)
    target: {{ target.name }} = db.get({{ target.name }}, {{ target.snake_name }}_ident)
    if target is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Target {{ target.name }} not found")
{%- if route.is_delete %}
    {%- if route.relation.side == 'one' %}
    self.relation_one_{{ target.snake_name }} = None
    {% else %}
    self.relation_many_{{ target.snake_name }}.remove(target)
    {% endif -%}
{% else %}
    {%- if route.relation.side == 'one' %}
    self.relation_one_{{ target.snake_name }} = target
    {% elif route.relation.side == 'many' %}
    self.relation_many_{{ target.snake_name }}.append(target)
    {% elif route.relation.side == 'both' %}
    self.{{ target.snake_name }}_associations.append(
        {{ route.relation.link_table.name }}(
        {{ target.snake_name }} = target,
        {%- for field_name, field in route.relation.link_fields.items() %}
        {{ field_name }} = {{ field_name }},
        {%- endfor -%}
        ))
    {% endif -%}
{%- endif %}
    db.commit()
    db.refresh(self)
    return self
{% endfor %}
{%- endif -%}
