import {
  NgModule,
  ModuleWithProviders,
  Type,
  Inject,
  InjectionToken,
} from '@angular/core';

import {
  RPC_CODEC,
  RPC_RWC,

  _ROOT_SUBSCRIBERS,
  _FEATURE_SUBSCRIBERS,
} from './core';

import {
  RPCClientRWC,
} from './client/RPCClientRWC';

import {
  RPCClientCodec,
} from './protocol';

import {
  SERVICES, RPCService,
} from './service';

import {
  SUBSCRIBERS, RPCSubscribeService,
} from './subscribe';

export interface RPCFeatureModuleConfig {
  subscribers?: Type<any>[];
}

export interface RPCRootModuleConfig {
  subscribers?: Type<any>[];
}

@NgModule({})
export class RPCRootModule {
  constructor(
    private rpcService: RPCService,
    private rpcSubscribeService: RPCSubscribeService,
    @Inject(_ROOT_SUBSCRIBERS) rootSubscribers: any[],
  ) {
    rootSubscribers.forEach((subscriber) => {
      rpcSubscribeService.addSubscriber(subscriber);
    });
  }
}

@NgModule({})
export class RPCFeatureModule {
  constructor(
    private rpcService: RPCService,
    private rpcSubscribeService: RPCSubscribeService,
    @Inject(_FEATURE_SUBSCRIBERS) featureSubscribersGroups: any[][],
    private root: RPCRootModule,
  ) {
    featureSubscribersGroups.forEach((featureSubscribers) => {
      featureSubscribers.forEach((subscriber) => {
        rpcSubscribeService.addSubscriber(subscriber);
      });
    });
  }
}

@NgModule({})
export class RPCModule {
  static forRoot(config: RPCRootModuleConfig): ModuleWithProviders {
    const subscribers = undefined === config.subscribers ? [] : config.subscribers;
    return {
      ngModule: RPCRootModule,
      providers: [
        subscribers,
        {
          provide: _ROOT_SUBSCRIBERS,
          deps: subscribers,
          useFactory: createSourceInstances,
        },
        SERVICES,
        SUBSCRIBERS,
      ],
    };
  }

  static forFeature(config: RPCFeatureModuleConfig): ModuleWithProviders {
    const subscribers = undefined === config.subscribers ? [] : config.subscribers;

    return {
      ngModule: RPCFeatureModule,
      providers: [
        subscribers,
        {
          provide: _FEATURE_SUBSCRIBERS,
          multi: true,
          deps: subscribers,
          useFactory: createSourceInstances,
        },
      ],
    };
  }
}

export function createSourceInstances(...instances: any[]) {
  return instances;
}
