/* Copyright CloudLinux Zug GmbH 2010-2017 All Rights Reserved
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * http://cloudlinux.com/docs/LICENSE.TXT
 */

import {Injector} from "@angular/core";
import {Observable} from "rxjs/Observable";
import {getTestBed, TestBed} from "@angular/core/testing";
import {
    TranslateService, TranslateLoader, LangChangeEvent, TranslationChangeEvent, TranslateModule,
    TranslateParser, MissingTranslationHandler
} from "@ngx-translate/core";
import {TranslateLocaleParser} from "../app/utils/TranslateLocaleParser";
import {TranslateLocaleMissingHandler} from "../app/utils/TranslateLocaleMissingHandler";
import {TranslateClass} from "../app/utils/pipes/translate";

declare var translateDict: any;
let translations: any = {"TEST": "This is a test"};
class FakeLoader implements TranslateLoader {
    getTranslation(lang: string): Observable<any> {
        translateDict = translations;
        return Observable.of(translations);
    }
}

describe('TranslateService', () => {
    let injector: Injector;
    let translate: TranslateService;
    let parser: TranslateParser;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [
                TranslateModule.forRoot({
                    loader: {provide: TranslateLoader, useClass: FakeLoader},
                    parser: {
                        provide: TranslateParser,
                        useClass: TranslateLocaleParser
                    },
                    missingTranslationHandler : {
                        provide: MissingTranslationHandler,
                        useClass: TranslateLocaleMissingHandler
                    }
                })
            ]
        });
        injector = getTestBed();
        translate = injector.get(TranslateService);
        parser = new TranslateLocaleParser();
    });

    afterEach(() => {
        injector = undefined;
        translate = undefined;
        translations = {"TEST": "This is a test"};
    });

    it('should be able to get translations with params {{}}', () => {
        translations = {"TEST": "This is a test {{param}}"};
        translate.use('en');

        translate.get('TEST', {param: 'with param'}).subscribe((res: string) => {
            expect(res).toEqual('This is a test with param');
        });

    });

    it('should be able to get translations with params {}', () => {
        translations = {"TEST": "This is a test {param}"};
        translate.use('en');

        translate.get('TEST', {param: 'with param'}).subscribe((res: string) => {
            expect(res).toEqual('This is a test with param');
        });

    });

    it('should be able to get translations with MissingTranslateHandler', () => {
        translate.use('en');

        translate.get( "This is a test {param}", {param: 'with param'}).subscribe((res: string) => {
            expect(res).toEqual('This is a test with param');
        });

        translate.get( "This is a test without any param").subscribe((res: string) => {
            expect(res).toEqual('This is a test without any param');
        });
    });

    it('should be able to get translations with params %()s', () => {
        translations = {"TEST": "This is a test %(param)s"};
        translate.use('en');

        translate.get('TEST', {param: 'with param'}).subscribe((res: string) => {
            expect(res).toEqual('This is a test with param');
        });

    });

    it('should be able to get translations with nested params', () => {
        translations = {"TEST": "This is a test {{param.value}}"};
        translate.use('en');

        translate.get('TEST', {param: {value: 'with param'}}).subscribe((res: string) => {
            expect(res).toEqual('This is a test with param');
        });

    });

    it('Parser is defined', () => {
        expect(TranslateParser).toBeDefined();

        expect(parser instanceof TranslateParser).toBeTruthy();
    });


    it('should interpolate', () => {
        expect(parser.interpolate("This is a {{ key }}", {key: "value"})).toEqual("This is a value");
        expect(parser.interpolate("This is a { key }", {key: "value"})).toEqual("This is a value");
        expect(parser.interpolate("This is a %( key )s", {key: "value"})).toEqual("This is a value");
    });

    it('should interpolate TranslateClass', () => {
        let translateClass = new TranslateClass();
        expect(translateClass.transform(["This is a {{ key }}", {key: "value"}])).toEqual("This is a value");
        expect(translateClass.transform(["This is a { key }",  {key: "value"}])).toEqual("This is a value");
        expect(translateClass.transform(["This is a %( key )s",  {key: "value"}])).toEqual("This is a value");
    });

    it('should interpolate with falsy values', () => {
        expect(parser.interpolate("This is a {{ key }}", {key: ""})).toEqual("This is a ");
        expect(parser.interpolate("This is a {{ key }}", {key: 0})).toEqual("This is a 0");

        expect(parser.interpolate("This is a { key }", {key: ""})).toEqual("This is a ");
        expect(parser.interpolate("This is a { key }", {key: 0})).toEqual("This is a 0");

        expect(parser.interpolate("This is a %( key )s", {key: ""})).toEqual("This is a ");
        expect(parser.interpolate("This is a %( key )s", {key: 0})).toEqual("This is a 0");
    });

    it('should interpolate with object properties', () => {
        expect(parser.interpolate("This is a {{ key1.key2 }}", {key1: {key2: "value2"}})).toEqual("This is a value2");
        expect(parser.interpolate("This is a {{ key1.key2.key3 }}", {key1: {key2: {key3: "value3"}}})).toEqual("This is a value3");

        expect(parser.interpolate("This is a { key1.key2 }", {key1: {key2: "value2"}})).toEqual("This is a value2");
        expect(parser.interpolate("This is a { key1.key2.key3 }", {key1: {key2: {key3: "value3"}}})).toEqual("This is a value3");

        expect(parser.interpolate("This is a %( key1.key2 )s", {key1: {key2: "value2"}})).toEqual("This is a value2");
        expect(parser.interpolate("This is a %( key1.key2.key3 )s", {key1: {key2: {key3: "value3"}}})).toEqual("This is a value3");
    });

    it('should get the addressed value', () => {
        expect(parser.getValue({key1: {key2: "value2"}}, 'key1.key2')).toEqual("value2");
        expect(parser.getValue({key1: {key2: "value"}}, 'keyWrong.key2')).not.toBeDefined();
        expect(parser.getValue({key1: {key2: {key3: "value3"}}}, 'key1.key2.key3')).toEqual("value3");
        expect(parser.getValue({key1: {key2: {key3: "value3"}}}, 'key1.keyWrong.key3')).not.toBeDefined();
        expect(parser.getValue({key1: {key2: {key3: "value3"}}}, 'key1.key2.keyWrong')).not.toBeDefined();


        expect(parser.getValue({'key1.key2': {key3: "value3"}}, 'key1.key2.key3')).toEqual("value3");
        expect(parser.getValue({key1: {'key2.key3': "value3"}}, 'key1.key2.key3')).toEqual("value3");
        expect(parser.getValue({'key1.key2.key3': "value3"}, 'key1.key2.key3')).toEqual("value3");
        expect(parser.getValue({'key1.key2': {key3: "value3"}}, 'key1.key2.keyWrong')).not.toBeDefined();
        expect(parser.getValue({
            'key1': "value1",
            'key1.key2': "value2"
        }, 'key1.key2')).toEqual("value2");

    });

    it('should interpolate missing translation with params in key', () => {
        translate.get('The unknown test message with {{ key }}', {key: 'param'}).subscribe((res: string) => {
            expect(res).toEqual('The unknown test message with param');
        });
    });

    it('should interpolate missing translation with translations in params', () => {
        translations = {
            "TEST": "This is a {{ key }}",
            "translate_param": "translated parameter"
        };
        translate.use('en');

        translate.get('TEST', {key: 'translate_param'}).subscribe((res: string) => {
            expect(res).toEqual('This is a translated parameter');
        });
    });

});
