describe('<md-tooltip> directive', function() {
  var $compile, $rootScope, $material, $timeout;
  var element;

  beforeEach(module('material.components.tooltip'));
  beforeEach(module('material.components.button'));
  beforeEach(inject(function(_$compile_, _$rootScope_, _$material_, _$timeout_){
    $compile   = _$compile_;
    $rootScope = _$rootScope_;
    $material  = _$material_;
    $timeout   = _$timeout_;
  }));
  afterEach(function() {
    // Make sure to remove/cleanup after each test
    element && element.scope().$destroy();
    element = undefined;
  });

  it('should preserve parent text', function(){
      buildTooltip(
        '<md-button>' +
          'Hello' +
         '<md-tooltip md-visible="testModel.isVisible">Tooltip</md-tooltip>' +
        '</md-button>'
      );

      expect(element.attr('aria-label')).toBeUndefined();
  });

  it('should label parent', function(){
      buildTooltip(
        '<md-button>' +
          '<md-tooltip md-visible="testModel.isVisible">' +
            'Tooltip' +
          '</md-tooltip>'+
        '</md-button>'
      );

      expect(element.attr('aria-label')).toEqual('Tooltip');
  });

  it('should not set parent to items with no pointer events', inject(function($window){
    spyOn($window, 'getComputedStyle').and.callFake(function(el) {
        return { 'pointer-events': el ? 'none' : '' };
    });

    buildTooltip(
      '<outer>' +
        '<inner>' +
          '<md-tooltip md-visible="testModel.isVisible">' +
            'Hello world' +
          '</md-tooltip>' +
        '</inner>' +
      '</outer>'
    );

    triggerEvent('mouseenter', true);
    expect($rootScope.testModel.isVisible).toBeUndefined();

  }));

  it('should show after tooltipDelay ms', function() {
    buildTooltip(
      '<md-button>' +
       'Hello' +
       '<md-tooltip md-visible="testModel.isVisible" md-delay="99">' +
         'Tooltip' +
       '</md-tooltip>' +
      '</md-button>'
    );

    triggerEvent('focus', true);
    expect($rootScope.testModel.isVisible).toBeFalsy();

    // Wait 1 below delay, nothing should happen
    $timeout.flush(98);
    expect($rootScope.testModel.isVisible).toBeFalsy();

    // Total 300 == tooltipDelay
    $timeout.flush(1);
    expect($rootScope.testModel.isVisible).toBe(true);

  });

  describe('show and hide', function() {

    it('should show and hide when visible is set',  function() {

      expect(findTooltip().length).toBe(0);

      buildTooltip(
        '<md-button>' +
          'Hello' +
          '<md-tooltip md-visible="testModel.isVisible">' +
            'Tooltip' +
          '</md-tooltip>' +
        '</md-button>'
      );

      showTooltip(true);

      expect(findTooltip().length).toBe(1);
      expect(findTooltip().hasClass('md-show')).toBe(true);

      showTooltip(false);

      expect(findTooltip().length).toBe(0);
    });

    it('should set visible on mouseenter and mouseleave', function() {
        buildTooltip(
          '<md-button>' +
             'Hello' +
             '<md-tooltip md-visible="testModel.isVisible">' +
              'Tooltip' +
            '</md-tooltip>' +
          '</md-button>'
        );

        triggerEvent('mouseenter');
        expect($rootScope.testModel.isVisible).toBe(true);

        triggerEvent('mouseleave');
        expect($rootScope.testModel.isVisible).toBe(false);
    });

    it('should set visible on focus and blur', function() {
      buildTooltip(
        '<md-button>' +
           'Hello' +
           '<md-tooltip md-visible="testModel.isVisible">' +
              'Tooltip' +
          '</md-tooltip>' +
        '</md-button>'
      );

      triggerEvent('focus');
      expect($rootScope.testModel.isVisible).toBe(true);

      triggerEvent('blur');
      expect($rootScope.testModel.isVisible).toBe(false);
    });

    it('should set visible on touchstart and touchend', function() {
      buildTooltip(
        '<md-button>' +
          'Hello' +
          '<md-tooltip md-visible="testModel.isVisible">' +
            'Tooltip' +
          '</md-tooltip>' +
        '</md-button>'
      );


      triggerEvent('touchstart');
      expect($rootScope.testModel.isVisible).toBe(true);

      triggerEvent('touchend');
      expect($rootScope.testModel.isVisible).toBe(false);

    });

    it('should not be visible on mousedown and then mouseleave', inject(function($document) {
      buildTooltip(
        '<md-button>' +
         'Hello' +
         '<md-tooltip md-visible="testModel.isVisible">' +
            'Tooltip' +
          '</md-tooltip>' +
        '</md-button>'
      );

      // Append element to DOM so it can be set as activeElement.
      $document[0].body.appendChild(element[0]);
      element[0].focus();
      triggerEvent('focus,mousedown');

      expect($document[0].activeElement).toBe(element[0]);
      expect($rootScope.testModel.isVisible).toBe(true);

      triggerEvent('mouseleave');
      expect($rootScope.testModel.isVisible).toBe(false);
    }));

    it('should not be visible when the window is refocused', inject(function($window, $document) {
      buildTooltip(
        '<md-button>' +
         'Hello' +
         '<md-tooltip md-visible="testModel.isVisible">' +
            'Tooltip' +
          '</md-tooltip>' +
        '</md-button>'
      );

      // Append element to DOM so it can be set as activeElement.
      $document[0].body.appendChild(element[0]);
      element[0].focus();
      triggerEvent('focus,mousedown');
      expect(document.activeElement).toBe(element[0]);

      triggerEvent('mouseleave');

      // Simulate tabbing away.
      angular.element($window).triggerHandler('blur');

      // Simulate focus event that occurs when tabbing back to the window.
      triggerEvent('focus');
      expect($rootScope.testModel.isVisible).toBe(false);
    }));
  });

  // ******************************************************
  // Internal Utility methods
  // ******************************************************

  function buildTooltip(markup) {

    element = $compile(markup)($rootScope);
    $rootScope.testModel = {};

    $rootScope.$apply();
    $material.flushOutstandingAnimations();

    return element;
  }

  function showTooltip(isVisible) {
    if (angular.isUndefined(isVisible)) isVisible = true;

    $rootScope.$apply('testModel.isVisible = ' + (isVisible ? 'true' : 'false') );
    $material.flushOutstandingAnimations();
  }

  function findTooltip() {
    return angular.element(document.body).find('md-tooltip');
  }


  function triggerEvent(eventType, skipFlush) {
    angular.forEach(eventType.split(','),function(name) {
      element.triggerHandler(name);
    });
    !skipFlush && $timeout.flush();
  }

});
