"""
Generates code for serializing / deserializing the model class to/from JSON.
It doesn't produce perfect code, as the functions expect to get access to some
values that only exist at runtime. However, the results are typically a good
starting point for writing your own, final version.

The code will be written to `uniserde_json.py` in the current working directory.
"""

from dataclasses import dataclass
from datetime import datetime
from pathlib import Path

import uniserde
from uniserde.type_hint import TypeHint


@dataclass
class SubModel:
    id: str
    timestamp: datetime
    reference_to_other_instance: str
    amount: int
    description: str
    events: list[str]


@dataclass
class Model:
    name: str
    subs: list[SubModel]
    sets: set[str]
    timestamp: datetime
    deleted: bool
    duration: float


def postprocess_code(
    code: str,
    method_name: str,
) -> str:
    # Cut off the header
    pos = code.find("):")
    assert pos != -1, "Cannot find the end of the function signature"

    code = code[pos + 2 :]

    # Replace silly names
    return code.replace("dateutil_parser", "dateutil.parser")


def main() -> None:
    # Prepare the code-generators for both serialization and deserialization
    #
    # Serialization
    serde = uniserde.JsonSerde()

    handler_builder = serde._serialization_cache._get_handler_builder(TypeHint(Model))
    ser_gen = serde._serialization_cache._write_code_from_handler_builder(
        handler_builder,
        TypeHint(Model),
    )

    # Deserialization
    handler_builder = serde._deserialization_cache._get_handler_builder(TypeHint(Model))
    deser_gen = serde._deserialization_cache._write_code_from_handler_builder(
        handler_builder,
        TypeHint(Model),
    )

    with Path("uniserde_json.py").open("w") as f:
        # Header text
        f.write(
            """
# This file was autogenerated by `uniserde`'s `write_model_code.py` script. It
# contains code for serializing / deserializing the model class to/from JSON.

from __future__ import annotations

from datetime import datetime, timedelta, timezone
import base64
import binascii
import uuid
import typing as t

import dateutil.parser


class SerdeError(Exception):
    def __init__(self, message: str) -> None:
        super().__init__(message)

    @property
    def message(self) -> str:
        return self.args[0]
""".strip()
        )
        f.write("\n\n\n")

        f.write("# Serialization\n")
        f.write("def as_json(self) -> dict[str, t.Any]:\n")
        f.write("    value_in = self\n")
        f.write(
            postprocess_code(
                ser_gen.resulting_code(),
                "as_json",
            )
        )
        f.write("\n\n\n")

        f.write("# Deserialization\n")
        f.write("def from_json(document: dict[str, t.Any]) -> Model:\n")
        f.write("    value_in = document\n")
        f.write(
            postprocess_code(
                deser_gen.resulting_code(),
                "from_json",
            )
        )
        f.write("\n")


if __name__ == "__main__":
    main()
