/**
 * @license
 * Copyright Google LLC 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.dev/license
 */

import {
  i18nCreateOpCodesToString,
  i18nRemoveOpCodesToString,
  i18nUpdateOpCodesToString,
  icuCreateOpCodesToString,
} from '../../src/render3/i18n/i18n_debug';
import {
  ELEMENT_MARKER,
  I18nCreateOpCode,
  I18nCreateOpCodes,
  I18nRemoveOpCodes,
  I18nUpdateOpCode,
  I18nUpdateOpCodes,
  ICU_MARKER,
  IcuCreateOpCode,
} from '../../src/render3/interfaces/i18n';

describe('i18n debug', () => {
  describe('i18nUpdateOpCodesToString', () => {
    it('should print nothing', () => {
      expect(i18nUpdateOpCodesToString([] as unknown as I18nUpdateOpCodes)).toEqual([]);
    });

    it('should print text opCode', () => {
      expect(
        i18nUpdateOpCodesToString([
          0b11,
          4,
          'pre ',
          -4,
          ' post',
          (1 << I18nUpdateOpCode.SHIFT_REF) | I18nUpdateOpCode.Text,
        ] as unknown as I18nUpdateOpCodes),
      ).toEqual([
        'if (mask & 0b11) { (lView[1] as Text).textContent = `pre ${lView[i-4]} post`; }',
      ]);
    });

    it('should print Attribute opCode', () => {
      // The `sanitizeFn` is written as actual function, compared to it being an arrow function.
      // This is done to make this test less reluctant to build process changes where e.g. an
      // arrow function might be transformed to a function declaration in ES5.
      const sanitizeFn = function (v: any) {
        return v;
      };

      expect(
        i18nUpdateOpCodesToString([
          0b01,
          8,
          'pre ',
          -4,
          ' in ',
          -3,
          ' post',
          (1 << I18nUpdateOpCode.SHIFT_REF) | I18nUpdateOpCode.Attr,
          'title',
          null,
          0b10,
          8,
          'pre ',
          -4,
          ' in ',
          -3,
          ' post',
          (1 << I18nUpdateOpCode.SHIFT_REF) | I18nUpdateOpCode.Attr,
          'title',
          sanitizeFn,
        ] as unknown as I18nUpdateOpCodes),
      ).toEqual([
        "if (mask & 0b1) { (lView[1] as Element).setAttribute('title', `pre ${lView[i-4]} in ${lView[i-3]} post`); }",
        `if (mask & 0b10) { (lView[1] as Element).setAttribute('title', (${sanitizeFn.toString()})(\`pre $\{lView[i-4]} in $\{lView[i-3]} post\`)); }`,
      ]);
    });

    it('should print icuSwitch opCode', () => {
      expect(
        i18nUpdateOpCodesToString([
          0b100,
          2,
          -5,
          (12 << I18nUpdateOpCode.SHIFT_REF) | I18nUpdateOpCode.IcuSwitch,
        ] as unknown as I18nUpdateOpCodes),
      ).toEqual(['if (mask & 0b100) { icuSwitchCase(12, `${lView[i-5]}`); }']);
    });

    it('should print icuUpdate opCode', () => {
      expect(
        i18nUpdateOpCodesToString([
          0b1000,
          1,
          (13 << I18nUpdateOpCode.SHIFT_REF) | I18nUpdateOpCode.IcuUpdate,
        ] as unknown as I18nUpdateOpCodes),
      ).toEqual(['if (mask & 0b1000) { icuUpdateCase(13); }']);
    });
  });

  describe('i18nMutateOpCodesToString', () => {
    it('should print nothing', () => {
      expect(icuCreateOpCodesToString([] as unknown as I18nCreateOpCodes)).toEqual([]);
    });

    it('should print text AppendChild', () => {
      expect(
        icuCreateOpCodesToString([
          'xyz',
          0,
          (1 << IcuCreateOpCode.SHIFT_PARENT) |
            (0 << IcuCreateOpCode.SHIFT_REF) |
            IcuCreateOpCode.AppendChild,
        ] as unknown as I18nCreateOpCodes),
      ).toEqual([
        'lView[0] = document.createTextNode("xyz")',
        '(lView[1] as Element).appendChild(lView[0])',
      ]);
    });

    it('should print element AppendChild', () => {
      expect(
        icuCreateOpCodesToString([
          ELEMENT_MARKER,
          'xyz',
          0,
          (1 << IcuCreateOpCode.SHIFT_PARENT) |
            (0 << IcuCreateOpCode.SHIFT_REF) |
            IcuCreateOpCode.AppendChild,
        ] as unknown as I18nCreateOpCodes),
      ).toEqual([
        'lView[0] = document.createElement("xyz")',
        '(lView[1] as Element).appendChild(lView[0])',
      ]);
    });

    it('should print comment AppendChild', () => {
      expect(
        icuCreateOpCodesToString([
          ICU_MARKER,
          'xyz',
          0,
          (1 << IcuCreateOpCode.SHIFT_PARENT) |
            (0 << IcuCreateOpCode.SHIFT_REF) |
            IcuCreateOpCode.AppendChild,
        ] as unknown as I18nCreateOpCodes),
      ).toEqual([
        'lView[0] = document.createComment("xyz")',
        '(lView[1] as Element).appendChild(lView[0])',
      ]);
    });

    it('should print Remove', () => {
      expect(i18nRemoveOpCodesToString([123] as unknown as I18nRemoveOpCodes)).toEqual([
        'remove(lView[123])',
      ]);
    });

    it('should print Attr', () => {
      expect(
        icuCreateOpCodesToString([
          (1 << IcuCreateOpCode.SHIFT_REF) | IcuCreateOpCode.Attr,
          'attr',
          'value',
        ] as unknown as I18nCreateOpCodes),
      ).toEqual(['(lView[1] as Element).setAttribute("attr", "value")']);
    });

    it('should print RemoveNestedIcu', () => {
      expect(i18nRemoveOpCodesToString([~123] as unknown as I18nRemoveOpCodes)).toEqual([
        'removeNestedICU(123)',
      ]);
    });
  });

  describe('i18nCreateOpCodesToString', () => {
    it('should print nothing', () => {
      expect(i18nCreateOpCodesToString([] as unknown as I18nCreateOpCodes)).toEqual([]);
    });

    it('should print text/comment creation', () => {
      expect(
        i18nCreateOpCodesToString([
          10 << I18nCreateOpCode.SHIFT,
          'text at 10', //
          (11 << I18nCreateOpCode.SHIFT) | I18nCreateOpCode.APPEND_EAGERLY,
          'text at 11, append', //
          (12 << I18nCreateOpCode.SHIFT) | I18nCreateOpCode.COMMENT,
          'comment at 12', //
          (13 << I18nCreateOpCode.SHIFT) |
            I18nCreateOpCode.COMMENT |
            I18nCreateOpCode.APPEND_EAGERLY,
          'comment at 13, append', //
        ] as unknown as I18nCreateOpCodes),
      ).toEqual([
        'lView[10] = document.createText("text at 10");',
        'lView[11] = document.createText("text at 11, append");',
        'parent.appendChild(lView[11]);',
        'lView[12] = document.createComment("comment at 12");',
        'lView[13] = document.createComment("comment at 13, append");',
        'parent.appendChild(lView[13]);',
      ]);
    });
  });
});
