// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @inward/extension-logging
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {
  bind,
  BindingScope,
  ContextTags,
  inject,
  Interceptor,
  InvocationContext,
  Provider,
  ValueOrPromise,
} from '@inward/context';
import {format} from 'util';
import {Logger} from 'winston';
import {LoggingBindings} from '../keys';

/**
 * A local interceptor that provides logging for method invocations.
 */
@bind({
  tags: {[ContextTags.KEY]: LoggingBindings.WINSTON_INVOCATION_LOGGER},
  scope: BindingScope.SINGLETON,
})
export class InvocationLoggingInterceptor implements Provider<Interceptor> {
  constructor(
    @inject(LoggingBindings.WINSTON_LOGGER)
    private logger: Logger,
  ) {}

  value() {
    return this.intercept.bind(this);
  }

  async intercept<T>(
    invocationCtx: InvocationContext,
    next: () => ValueOrPromise<T>,
  ) {
    try {
      this.logger.log(
        'verbose',
        format(
          'invoking %s with:',
          invocationCtx.targetName,
          invocationCtx.args,
        ),
      );
      const result = await next();
      this.logger.log(
        'verbose',
        format('returned from %s:', invocationCtx.targetName, result),
      );
      return result;
    } catch (err) {
      this.logger.log(
        'error',
        format('error from %s', invocationCtx.targetName, err),
      );
      throw err;
    }
  }
}
