<?php

namespace Shm\ShmRPC\ShmRPCCodeGen;

use Shm\ShmTypes\BaseType;

class ShmRPCCodeGenExtensionsStore
{

    private static array $extensions = [];

    public static function addExtension(string $key, BaseType $extension)
    {
        self::$extensions[$key] = $extension;
    }


    public static function tsClass(): string
    {




        $storeType = [];

        $storeInputType = [];

        $addToStoreFunctionCode = [];

        $defaultStore = [];

        $getByIDFunctionsCode = [];
        $getByIDsFunctionsCode = [];

        foreach (self::$extensions as $key => $extension) {
            $storeType[] = $key . ':  {[key:string]: ' . $extension->tsType()->getTsTypeName() . '}';
            $storeInputType[] = $key . '?:  ' . $extension->tsType()->getTsTypeName() . '[]';

            $defaultStore[] = $key . ': {}';


            $getByIDFunctionsCode[] = 'public static ' . $key . 'ByID(id?: string | null): ' . $extension->tsType()->getTsTypeName() . ' | null {
            
            
            if(!id){
                return null;
            }

            if(this.store.' . $key . '?.[id]){
                return this.store.' . $key . '[id];
            }else{
               console.info("📕 Extension ' . $key . ' not found by ID: " + id);
             }

            return null;
            }';

            $getByIDsFunctionsCode[] = 'public static ' . $key . 'ByIDs(ids?: string[] | null): ' . $extension->tsType()->getTsTypeName() . '[] {
            
            if(!ids){
                return [];
            }

            const result = [];
            for(const id of ids){
                if(this.store.' . $key . '[id]){
                    result.push(this.store.' . $key . '[id]);
                }
            }

            if(result.length === 0){
                console.info("📕 Extensions ' . $key . ' not found by IDs: " + ids.join(", "));
            }

            return result;

            }';

            $addToStoreFunctionCode[] = 'if(value?.' . $key . ' && value?.' . $key . '.length > 0) {
            
            for(const item of value?.' . $key . ') {
                 if(item?._id){
                     this.store.' . $key . '[item._id] = item;
                 }
            }

            }';
        }


        $addToStoreFunctionCode = implode('\n', $addToStoreFunctionCode);

        $defaultStore = implode(', ', $defaultStore);

        $getByIDFunctionsCode = implode('\n', $getByIDFunctionsCode);

        $getByIDsFunctionsCode = implode('\n', $getByIDsFunctionsCode);

        $allExtensionsKeys = '("' . implode('" | "', array_keys(self::$extensions)) . '")[]';

        $code = '
        

        type DefaultExtensionsType = ' . $allExtensionsKeys . ';
        
        type ExtensionsStoreType = {' . implode(', ', $storeType) . '};
        
        type ExtensionsStoreInputType = {' . implode(', ', $storeInputType) . '};
        
        export class ExtensionsStore {
        
          private static storage: { save: (key: string, value: string) => Promise<void>; get: (key: string) => Promise<string | null> } | null = null;


  /* 
  
  //Убрал так как объем данных может быть большим и не хватает памяти,
  //Нужно пересмотреть способ кеширования
  public static setStorage(storage: { save: (key: string, value: string) => Promise<void>; get: (key: string) => Promise<string | null> }): void {
      this.storage = storage;
   }*/

   public static async loadFromStorage(): Promise<void> {
      if (this.storage) {
         const extensionsStore = await this.storage.get("extensionsStore");
         if (extensionsStore) {
            try {
               let _extensionsStore: ExtensionsStoreType = JSON.parse(extensionsStore);

               map(_extensionsStore, (value: any, key: keyof ExtensionsStoreType) => {
                  if (value) {

                     if (this.store?.[key]) {
                        //@ts-ignore
                        this.store[key] = {
                           //@ts-ignore
                           ...this.store[key],
                           ...value
                        };

                     } else {
                        //@ts-ignore
                        this.store[key] = value;
                     }

                  }
               });

            } catch (error) {
               console.error("⚠️ Ошибка при загрузке extensionsStore из storage:", error);
            }

         }
      }
   }

            private static saveToStorage = debounce(() => {

                if (this.storage) {
                   this.storage.save("extensionsStore", JSON.stringify(toJS(this.store)));
                }


            }, 1000);

        private static store: ExtensionsStoreType = observable({' . $defaultStore . '});
        
        public static addToStore(value: ExtensionsStoreInputType) {
        
        ' . $addToStoreFunctionCode . '


         this.saveToStorage();
        }

        ' . $getByIDFunctionsCode . '


        ' . $getByIDsFunctionsCode . '
        
          }';

        return $code;
    }
}
