from types import LambdaType, UnionType
from returns.pipeline import is_successful
from typing import List, TypeVar
from returns.result import Result, Success, Failure
import os
from model.robossembler_assets import (
    MappingInstanceAtModel,
    RobossemblerAssets,
    Instance,
)
import re
import pathlib
from repository.file_system import FileSystemRepository
from model.robossembler_assets import Physics
from argparse import ArgumentParser


T = TypeVar("T")


class JsonReaderAndModelMapperUseCase:
    def call(path: str, model: T) -> Result[T, str]:
        try:
            if not re.search("^(.+)\/([^\/]+)$", path):
                return Failure("path not valid")
            if model.from_dict == None:
                return Failure("Model is not have mapping method from_dict")
            return Success(model.from_dict(FileSystemRepository.readJSON(path=path)))
        except:
            return Failure("JsonReaderAndModelMapperUseCase unknown error")


class MappingInstanceAtModelToSdfUseCase:
    def call(instances: List[MappingInstanceAtModel]) -> Result[List[str], str]:
        try:
            return Success(list(map(lambda el: el.toSDF(), instances)))
        except:
            return Failure("MappingInstanceAtModelToSdfUseCase unknown error")


class MappingSdfWorldToPhysicsModelUseCase:
    def call(physicModel: Physics) -> Result[List[str], str]:
        try:
            return Success(Physics.toSDF(physicModel))
        except:
            return Failure("MappingInstanceAtModelToSdfUseCase unknown error")


class FormationOfTheSDFUseCase:
    def call(worldTag: str, modelsTags: List[str], path: str) -> Result[bool, str]:
        path = str(pathlib.Path(path).parent.resolve()) + "/"
        if modelsTags == None:
            return Failure("FormationOfTheSDFUseCase modelsTags is None")
        if worldTag == None:
            return Failure("FormationOfTheSDFUseCase worldTag is None")

        FileSystemRepository.writeFile(
            data=worldTag.replace("{models}", "\n".join(modelsTags)),
            filePath=path,
            fileName="world.sdf",
        )
        return Success(True)


def main():
    parser = ArgumentParser()
    parser.add_argument("--path", help="need path .json")
    args = parser.parse_args()

    if args.path == None:
        parser.print_help()
        return
    path = args.path
    jsonReaderAndModelMapperUseCase = JsonReaderAndModelMapperUseCase.call(
        path=path, model=RobossemblerAssets
    )

    if not is_successful(jsonReaderAndModelMapperUseCase):
        return
    robossemblerAssets = jsonReaderAndModelMapperUseCase.value_or(None)

    instanceSdfModel = MappingInstanceAtModelToSdfUseCase.call(
        instances=robossemblerAssets.getAllAssetsInstanceAtModel()
    )

    sdfWorld = MappingSdfWorldToPhysicsModelUseCase.call(
        physicModel=robossemblerAssets.physics
    )

    FormationOfTheSDFUseCase.call(
        worldTag=sdfWorld.value_or(None),
        modelsTags=instanceSdfModel.value_or(None),
        path=path,
    )


main()
