/**
 * @license
 * Copyright Google Inc. All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

import * as ts from 'typescript';

import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
import {DtsMetadataReader, LocalMetadataRegistry} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {ClassDeclaration, TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
import {DirectiveDecoratorHandler} from '../src/directive';


describe('DirectiveDecoratorHandler', () => {
  it('should use the `ReflectionHost` to detect class inheritance', () => {
    const {program} = makeProgram([
      {
        name: 'node_modules/@angular/core/index.d.ts',
        contents: 'export const Directive: any;',
      },
      {
        name: 'entry.ts',
        contents: `
          import {Directive} from '@angular/core';

          @Directive({selector: 'test-dir-1'})
          export class TestDir1 {}

          @Directive({selector: 'test-dir-2'})
          export class TestDir2 {}
        `,
      },
    ]);

    const checker = program.getTypeChecker();
    const reflectionHost = new TestReflectionHost(checker);
    const evaluator = new PartialEvaluator(reflectionHost, checker);
    const metaReader = new LocalMetadataRegistry();
    const dtsReader = new DtsMetadataReader(checker, reflectionHost);
    const scopeRegistry = new LocalModuleScopeRegistry(
        metaReader, new MetadataDtsModuleScopeResolver(dtsReader, null), new ReferenceEmitter([]),
        null);
    const handler = new DirectiveDecoratorHandler(
        reflectionHost, evaluator, scopeRegistry, NOOP_DEFAULT_IMPORT_RECORDER, false);

    const analyzeDirective = (dirName: string) => {
      const DirNode = getDeclaration(program, 'entry.ts', dirName, isNamedClassDeclaration);

      const detected = handler.detect(DirNode, reflectionHost.getDecoratorsOfDeclaration(DirNode));
      if (detected === undefined) {
        throw new Error(`Failed to recognize @Directive (${dirName}).`);
      }

      const {analysis} = handler.analyze(DirNode, detected.metadata);
      if (analysis === undefined) {
        throw new Error(`Failed to analyze @Directive (${dirName}).`);
      }

      return analysis;
    };

    // By default, `TestReflectionHost#hasBaseClass()` returns `false`.
    const analysis1 = analyzeDirective('TestDir1');
    expect(analysis1.meta.usesInheritance).toBe(false);

    // Tweak `TestReflectionHost#hasBaseClass()` to return true.
    reflectionHost.hasBaseClassReturnValue = true;

    const analysis2 = analyzeDirective('TestDir2');
    expect(analysis2.meta.usesInheritance).toBe(true);
  });
});

// Helpers
class TestReflectionHost extends TypeScriptReflectionHost {
  hasBaseClassReturnValue = false;

  hasBaseClass(clazz: ClassDeclaration): boolean { return this.hasBaseClassReturnValue; }
}
