/**
 * @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 {Component, Directive, TemplateRef, ViewContainerRef} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {fixmeIvy, onlyInIvy, polyfillGoogGetMsg} from '@angular/private/testing';
@Directive({
  selector: '[tplRef]',
})
class DirectiveWithTplRef {
  constructor(public vcRef: ViewContainerRef, public tplRef: TemplateRef<{}>) {}
  ngOnInit() { this.vcRef.createEmbeddedView(this.tplRef, {}); }
}
@Component({selector: 'my-comp', template: ''})
class MyComp {
  name = 'John';
  items = ['1', '2', '3'];
  visible = true;
  age = 20;
  count = 2;
  otherLabel = 'other label';
}
const TRANSLATIONS: any = {
  'one': 'un',
  'two': 'deux',
  'more than two': 'plus que deux',
  'ten': 'dix',
  'twenty': 'vingt',
  'other': 'autres',
  'Hello': 'Bonjour',
  'Hello {$interpolation}': 'Bonjour {$interpolation}',
  'Bye': 'Au revoir',
  'Item {$interpolation}': 'Article {$interpolation}',
  '\'Single quotes\' and "Double quotes"': '\'Guillemets simples\' et "Guillemets doubles"',
  'My logo': 'Mon logo',
  '{$startTagSpan}My logo{$tagImg}{$closeTagSpan}':
      '{$startTagSpan}Mon logo{$tagImg}{$closeTagSpan}',
  '{$startTagNgTemplate} Hello {$closeTagNgTemplate}{$startTagNgContainer} Bye {$closeTagNgContainer}':
      '{$startTagNgTemplate} Bonjour {$closeTagNgTemplate}{$startTagNgContainer} Au revoir {$closeTagNgContainer}',
  '{$startTagNgTemplate}{$startTagSpan}Hello{$closeTagSpan}{$closeTagNgTemplate}{$startTagNgContainer}{$startTagSpan_1}Hello{$closeTagSpan}{$closeTagNgContainer}':
      '{$startTagNgTemplate}{$startTagSpan}Bonjour{$closeTagSpan}{$closeTagNgTemplate}{$startTagNgContainer}{$startTagSpan_1}Bonjour{$closeTagSpan}{$closeTagNgContainer}',
  '{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}':
      '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autres}}',
  '{VAR_SELECT, select, 10 {10 - {$startBoldText}ten{$closeBoldText}} 20 {20 - {$startItalicText}twenty{$closeItalicText}} other {{$startTagDiv}{$startUnderlinedText}other{$closeUnderlinedText}{$closeTagDiv}}}':
      '{VAR_SELECT, select, 10 {10 - {$startBoldText}dix{$closeBoldText}} 20 {20 - {$startItalicText}vingt{$closeItalicText}} other {{$startTagDiv}{$startUnderlinedText}autres{$closeUnderlinedText}{$closeTagDiv}}}',
  '{VAR_SELECT_2, select, 10 {ten - {VAR_SELECT, select, 1 {one} 2 {two} other {more than two}}} 20 {twenty - {VAR_SELECT_1, select, 1 {one} 2 {two} other {more than two}}} other {other}}':
      '{VAR_SELECT_2, select, 10 {dix - {VAR_SELECT, select, 1 {un} 2 {deux} other {plus que deux}}} 20 {vingt - {VAR_SELECT_1, select, 1 {un} 2 {deux} other {plus que deux}}} other {autres}}'
};
const getFixtureWithOverrides = (overrides = {}) => {
  TestBed.overrideComponent(MyComp, {set: overrides});
  const fixture = TestBed.createComponent(MyComp);
  fixture.detectChanges();
  return fixture;
};
onlyInIvy('Ivy i18n logic').describe('i18n', function() {
  beforeEach(() => {
    polyfillGoogGetMsg(TRANSLATIONS);
    TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithTplRef]});
  });
  describe('attributes', () => {
    it('should translate static attributes', () => {
      const title = 'Hello';
      const template = `
`;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element.title).toBe('Bonjour');
    });
    it('should support interpolation', () => {
      const title = 'Hello {{ name }}';
      const template = ``;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element.title).toBe('Bonjour John');
    });
    it('should support interpolation with custom interpolation config', () => {
      const title = 'Hello {% name %}';
      const template = ``;
      const interpolation = ['{%', '%}'] as[string, string];
      const fixture = getFixtureWithOverrides({template, interpolation});
      const element = fixture.nativeElement.firstChild;
      expect(element.title).toBe('Bonjour John');
    });
    it('should correctly bind to context in nested template', () => {
      const title = 'Item {{ id }}';
      const template = `
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      for (let i = 0; i < element.children.length; i++) {
        const child = element.children[i];
        expect((child as any).innerHTML).toBe(``);
      }
    });
    fixmeIvy('FW-904: i18n attributes placed on i18n root node don\'t work')
        .it('should work correctly when placed on i18n root node', () => {
          const title = 'Hello {{ name }}';
          const content = 'Hello';
          const template = `
            ${content}
          `;
          const fixture = getFixtureWithOverrides({template});
          const element = fixture.nativeElement.firstChild;
          expect(element.title).toBe('Bonjour John');
          expect(element).toHaveText('Bonjour');
        });
    it('should add i18n attributes on self-closing tags', () => {
      const title = 'Hello {{ name }}';
      const template = ` `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element.title).toBe('Bonjour John');
    });
  });
  describe('nested nodes', () => {
    it('should handle static content', () => {
      const content = 'Hello';
      const template = `
`;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element.title).toBe('Bonjour John');
    });
  });
  describe('nested nodes', () => {
    it('should handle static content', () => {
      const content = 'Hello';
      const template = `${content}
`;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element).toHaveText('Bonjour');
    });
    it('should support interpolation', () => {
      const content = 'Hello {{ name }}';
      const template = `${content}
`;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element).toHaveText('Bonjour John');
    });
    it('should support interpolation with custom interpolation config', () => {
      const content = 'Hello {% name %}';
      const template = `${content}
`;
      const interpolation = ['{%', '%}'] as[string, string];
      const fixture = getFixtureWithOverrides({template, interpolation});
      const element = fixture.nativeElement.firstChild;
      expect(element).toHaveText('Bonjour John');
    });
    it('should properly escape quotes in content', () => {
      const content = `'Single quotes' and "Double quotes"`;
      const template = `${content}
`;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element).toHaveText('\'Guillemets simples\' et "Guillemets doubles"');
    });
    it('should correctly bind to context in nested template', () => {
      const content = 'Item {{ id }}';
      const template = `
          
        `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      for (let i = 0; i < element.children.length; i++) {
        const child = element.children[i];
        expect(child).toHaveText(`Article ${i + 1}`);
      }
    });
    it('should handle i18n attributes inside i18n section', () => {
      const title = 'Hello {{ name }}';
      const template = `
          
        `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      const content = ``;
      expect(element.innerHTML).toBe(content);
    });
    it('should handle i18n blocks in nested templates', () => {
      const content = 'Hello {{ name }}';
      const template = `
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element.children[0]).toHaveText('Bonjour John');
    });
    it('should ignore i18n attributes on self-closing tags', () => {
      const template = ' ';
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element.innerHTML).toBe(template.replace(' i18n', ''));
    });
    it('should handle i18n attribute with directives', () => {
      const content = 'Hello {{ name }}';
      const template = `
';
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element.innerHTML).toBe(template.replace(' i18n', ''));
    });
    it('should handle i18n attribute with directives', () => {
      const content = 'Hello {{ name }}';
      const template = `
        ${content}
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element).toHaveText('Bonjour John');
    });
  });
  describe('ng-container and ng-template support', () => {
    it('should handle single translation message within ng-container', () => {
      const content = 'Hello {{ name }}';
      const template = `
        ${content}
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element).toHaveText('Bonjour John');
    });
    it('should handle single translation message within ng-template', () => {
      const content = 'Hello {{ name }}';
      const template = `
        ${content}
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element).toHaveText('Bonjour John');
    });
    it('should be able to act as child elements inside i18n block (plain text content)', () => {
      const hello = 'Hello';
      const bye = 'Bye';
      const template = `
        
          
            ${hello}
          
          
            ${bye}
          
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element.textContent.replace(/\s+/g, ' ').trim()).toBe('Bonjour Au revoir');
    });
    fixmeIvy(
        'FW-910: Invalid placeholder structure generated when using  with content that contains tags')
        .it('should be able to act as child elements inside i18n block (text + tags)', () => {
          const content = 'Hello';
          const template = `
            
              
                ${content}
              
              
                ${content}
              
            
          `;
          const fixture = getFixtureWithOverrides({template});
          const element = fixture.nativeElement;
          const spans = element.getElementsByTagName('span');
          for (let i = 0; i < spans.length; i++) {
            const child = spans[i];
            expect((child as any).innerHTML).toBe('Bonjour');
          }
        });
    it('should handle self-closing tags as content', () => {
      const label = 'My logo';
      const content = `${label} `;
      const template = `
        
          ${content}
        
        
          ${content}
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      const spans = element.getElementsByTagName('span');
      for (let i = 0; i < spans.length; i++) {
        const child = spans[i];
        expect(child).toHaveText('Mon logo');
      }
    });
  });
  describe('ICU logic', () => {
    it('should handle single ICUs', () => {
      const template = `
`;
      const template = `
        
          ${content}
        
        
          ${content}
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      const spans = element.getElementsByTagName('span');
      for (let i = 0; i < spans.length; i++) {
        const child = spans[i];
        expect(child).toHaveText('Mon logo');
      }
    });
  });
  describe('ICU logic', () => {
    it('should handle single ICUs', () => {
      const template = `
        {age, select, 10 {ten} 20 {twenty} other {other}}
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element).toHaveText('vingt');
    });
    it('should support ICUs generated outside of i18n blocks', () => {
      const template = `
        {age, select, 10 {ten} 20 {twenty} other {other}}
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element).toHaveText('vingt');
    });
    it('should support interpolation', () => {
      const template = `
        {age, select, 10 {ten} other {{{ otherLabel }}}}
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element).toHaveText(fixture.componentInstance.otherLabel);
    });
    it('should support interpolation with custom interpolation config', () => {
      const template = `
        {age, select, 10 {ten} other {{% otherLabel %}}}
      `;
      const interpolation = ['{%', '%}'] as[string, string];
      const fixture = getFixtureWithOverrides({template, interpolation});
      const element = fixture.nativeElement;
      expect(element).toHaveText(fixture.componentInstance.otherLabel);
    });
    it('should handle ICUs with HTML tags inside', () => {
      const template = `
        
          {age, select, 10 {10 - 
ten} 20 {20 - 
twenty} other {
other
}}
        
              {age, select, 10 {ten} 20 {twenty} other {other}} - 
              {count, select, 1 {one} 2 {two} other {more than two}}
            
          `;
          const fixture = getFixtureWithOverrides({template});
          const element = fixture.nativeElement.firstChild;
          expect(element).toHaveText('vingt - deux');
        });
    fixmeIvy('FW-906: Multiple ICUs wrapped in HTML tags in one i18n block throw an error')
        .it('should handle multiple ICUs in one i18n block wrapped in HTML elements', () => {
          const template = `
            
              
                {age, select, 10 {ten} 20 {twenty} other {other}}
              
              
                {count, select, 1 {one} 2 {two} other {more than two}}
              
            
          `;
          const fixture = getFixtureWithOverrides({template});
          const element = fixture.nativeElement.firstChild;
          const spans = element.getElementsByTagName('span');
          expect(spans.length).toBe(2);
          expect(spans[0].innerHTML).toBe('vingt');
          expect(spans[1].innerHTML).toBe('deux');
        });
    it('should handle ICUs inside a template in i18n block', () => {
      const template = `
            
              
                {age, select, 10 {ten} 20 {twenty} other {other}}
              
            
          `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      const spans = element.getElementsByTagName('span');
      expect(spans.length).toBe(1);
      expect(spans[0]).toHaveText('vingt');
    });
    it('should handle nested icus', () => {
      const template = `
        
          {age, select,
            10 {ten - {count, select, 1 {one} 2 {two} other {more than two}}}
            20 {twenty - {count, select, 1 {one} 2 {two} other {more than two}}}
            other {other}}
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement.firstChild;
      expect(element).toHaveText('vingt - deux');
    });
    it('should handle ICUs inside ', () => {
      const template = `
        
          {age, select, 10 {ten} 20 {twenty} other {other}}
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element).toHaveText('vingt');
    });
    it('should handle ICUs inside ', () => {
      const template = `
        
          {age, select, 10 {ten} 20 {twenty} other {other}}
        
      `;
      const fixture = getFixtureWithOverrides({template});
      const element = fixture.nativeElement;
      expect(element).toHaveText('vingt');
    });
  });
});