from typing import Any
from lptp.server import manager
from datetime import datetime, UTC
from lptp.types.pds.types.base import FieldType


def hex_str(num: int) -> str:
    hex_data = hex(num)[2:]
    return "0x" + ("0" if len(hex_data) == 1 else "") + hex_data

def generate_proc_file(filename: str, manager: "manager.Manager") -> None:
    file_content = f"""
from lptp.client.client import LPTPClient
from lptp.exceptions.client import ProcedureError
from lptp.types.pds import DataField, ProcedureDataStructure
from typing import *

# This file autogenerated on {datetime.now(UTC).strftime('%d.%m.%Y %H:%M:%S')} UTC
# Total procedure count is {len(manager._procedures)}

class ProcedureManager:
    client: LPTPClient

    hash = "{manager.hash}"

    def __init__(self, client: LPTPClient = None) -> None:
        if client and not isinstance(client, LPTPClient):
            raise TypeError("client should be instance of LPTPClient")
        self.client = client
        self.client.hash = self.hash

    async def __aenter__(self) -> Self:
        await self.client.__aenter__()
        return self
    
    async def __aexit__(self, exc_type, exc, tb) -> None:
        return await self.client.__aexit__(exc_type, exc, tb)
"""
    for procedure in manager._procedures:
        params = ", ".join(["self"] + [
            f"{field.varname}: {field.name}%s" % (" = " + str(field.default) if field.have_default else "")
            for field in procedure.get_fields()
        ])
        fields = ",\n\t\t\t\t".join([
            f"DataField({hex_str(field.name)}, {field.varname})"
            for field in procedure.get_fields()
        ])
        file_content += f"""
    async def {procedure.get_func_name()}({params}) -> {procedure.get_return().type_name}:
        res = await self.client.send_procedure(
            {hex_str(procedure.name)},
            {hex_str(procedure.subtype)},
            ProcedureDataStructure([
                {fields}
            ])
        )
        if not res.ok:
            raise ProcedureError("Server returned %s status" % res.status_code)
        return res.field.data
"""
        
        with open(filename, "w") as f:
            f.write(file_content)