<?php

namespace Shm\ShmRPC\ShmRPCCodeGen;

use Shm\ShmUtils\ShmUtils;
use Shm\ShmTypes\BaseType;
use Shm\ShmTypes\StructureType;

class ShmRPCRequestCode
{



    private BaseType $type;
    private BaseType | null $args;
    private string $key;

    private $formData = false;

    public function __construct(
        BaseType $type,
        BaseType | null $args,
        string $key,
        $formData = false
    ) {
        $this->type = $type;
        $this->args = $args;
        $this->key = $key;
        $this->formData = $formData;
    }


    private function  functionName(): string
    {
        return $this->key; // ShmUtils::onlyLetters($this->key);
    }

    private function paramsForFunction(): string
    {
        if (isset($this->args)) {

            return 'params: ' . $this->args->keyIfNot($this->key)->tsInputType()->getTsTypeName();
        }
        return "";
    }


    public function paramsType(): string
    {
        if (isset($this->args)) {

            return $this->args->keyIfNot($this->key)->tsInputType()->getTsTypeName();
        }
        return "{}";
    }



    private function getExtensionsStructure(BaseType $type, $count = 0): array
    {

        $extensionsStructure = $type->extensionsStructure();

        $extensionsCollection = array_keys($extensionsStructure);



        if ($count < 3) {
            foreach ($extensionsStructure as $extension => $structure) {


                [$subExtensionsStructure, $subExtensionsCollection] = $this->getExtensionsStructure($structure, $count + 1);

                $extensionsStructure = [...$extensionsStructure, ...$subExtensionsStructure];


                foreach ($subExtensionsCollection as $subExtension) {

                    $extensionsCollection[] = $extension . '->' . $subExtension;
                }
            }
        }

        return [
            $extensionsStructure,
            $extensionsCollection,
        ];
    }



    public function initialize(): string
    {


        if ($this->formData) {

            return "{$this->functionName()}: (formData:FormData) => {
            return rpcClient.callFormData<{$this->type->tsType()->getTsTypeName()} | null>(
               '{$this->key}', formData
            );
             },";
        } else {

            [$extensionsStructure, $extensionsCollection] = $this->getExtensionsStructure($this->type, 1);



            $extensionsType = "";

            $extensionsGenericType = 'null';

            $useExtensions = false;

            if (count($extensionsCollection) > 0) {

                $extensionsType = '"' . implode('" | "', $extensionsCollection) . '"';




                $extensionsType = 'extensions?: Array<' . $extensionsType . '>';

                $extensionsGenericType = [];
                foreach ($extensionsStructure as $key => $val) {
                    ShmRPCCodeGenExtensionsStore::addExtension($key, $val);
                    $extensionsGenericType[] = $key . '?: ' . $val->tsType()->getTsTypeName() . '[] | null ';
                }


                $extensionsGenericType = '{' . implode(', ', $extensionsGenericType) . '}';

                $useExtensions = true;
            }



            $params = [];
            $rpcFunctionParams = [];

            $paramsForFunction = $this->paramsForFunction();
            if ($paramsForFunction) {
                $params[] = $paramsForFunction;
                $rpcFunctionParams[] = 'params';
            } else {
                $rpcFunctionParams[] = '{}';
            }

            if ($useExtensions) {
                $params[] = $extensionsType;
                $rpcFunctionParams[] = 'extensions';
            } else {
                $rpcFunctionParams[] = '[]';
            }

            $params = implode(', ', $params);
            $rpcFunctionParams = implode(', ', $rpcFunctionParams);



            if ($useExtensions) {


                return "{$this->functionName()}: ( $params) => {
            return rpcClient.call<{$this->paramsType()}, {$this->type->tsType()->getTsTypeName()} | null, {$extensionsGenericType}>(
               '{$this->key}',{$rpcFunctionParams}
            );
             },";
            } else {
                return "{$this->functionName()}: ( $params) => {
            return rpcClient.call<{$this->paramsType()}, {$this->type->tsType()->getTsTypeName()} | null, null>(
               '{$this->key}',{$rpcFunctionParams}
            );
             },";
            }
        }
    }
}