import asyncio

from jinja2 import Template

from pynspd.client import get_async_client
from pynspd.schemas.layer_configs import Card, CardField, LayerNode, LayersTree

CLIENT = get_async_client()


TYPES_TEMPLATE = """# autogenerated
from typing import Literal


LayerTitle = Literal[
    {%- for layer in layers %}
    "{{ layer.title }}",
    {%- endfor %}
]
"""

SCHEMAS_TEMPLATE = """# autogenerated
from typing import Union, Annotated, Optional, override
from datetime import date

from geojson_pydantic import Feature
from pydantic import Field

from pynspd.schemas.geometries import Point, LineString, Polygon, MultiPolygon
from pynspd.schemas.layer_configs import LayerNode
from pynspd.schemas.feature import _BaseFeature
from pynspd.schemas.properties import Properties, OptionProperties


{% for category_id, fields in layers_fields.items() %}
class Options{{ category_id }}(OptionProperties): {% if fields|length == 0 %}...{% endif %}
    {%- for field in fields %}
    {{ field.key_value }}: Optional[{{field.key_type}}] = None
    \"\"\"{{field.key_name}}{% if field.postfix != None %} ({{ field.postfix }}){% endif %}\"\"\"
    {%- endfor %}
{% endfor %}


{% for layer in layers %}
class Layer{{ layer.layer_id }}Feature(_BaseFeature[
    {%- if layer.geometry_type == 'Polygon' %}
    Union[MultiPolygon, Polygon, Point],
    {% else %}
    {{ layer.geometry_type }},
    {% endif -%}
    Properties[Options{{ layer.category_id }}]
]):
    \"\"\"{{ layer.title }}\"\"\"
    layer_meta = LayerNode.model_validate({{ layer.model_dump(by_alias=True) }})
{% endfor %}
"""


def generate_files(layers: list[LayerNode], layers_fields: dict[int, Card]):
    output = Template(SCHEMAS_TEMPLATE).render(
        layers=layers, layers_fields=layers_fields
    )
    with open("src/pynspd/schemas/_autogen_features.py", "w", encoding="utf-8") as file:
        file.write(output)
    output = Template(TYPES_TEMPLATE).render(layers=layers)
    with open("src/pynspd/types/_autogen_layers.py", "w", encoding="utf-8") as file:
        file.write(output)


async def get_layer_tree() -> LayersTree:
    r = (
        await CLIENT.get("/api/geoportal/v1/layers-theme-tree", params={"themeId": 1})
    ).raise_for_status()
    tree = LayersTree.model_validate(r.json())
    return tree


async def get_category_card(category_id: int) -> tuple[int, list[CardField]]:
    r = (
        await CLIENT.get(f"/api/geoportal/v1/geom-card-display-settings/{category_id}")
    ).raise_for_status()
    card = Card.model_validate(r.json())
    fields = []
    for field in card.card:
        if field.key_value == "-":
            continue
        if field.key_value == "":
            continue
        if not field.key_value.isascii():
            continue
        if " " in field.key_value:
            continue
        fields.append(field)
    return category_id, fields


async def get_layers_fields(layers: list[LayerNode]) -> dict[int, list[CardField]]:
    layers_fields = {}
    categories = list(set([i.category_id for i in layers]))
    result = await asyncio.gather(*[get_category_card(i) for i in categories])
    layers_fields = dict(result)
    return layers_fields


async def main():
    tree = await get_layer_tree()
    layers = tree.layers
    layers_fields = await get_layers_fields(layers)
    generate_files(layers, layers_fields)


if __name__ == "__main__":
    asyncio.run(main())
