/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import {merge} from 'lodash';

const {ThemeConfigSchema, DEFAULT_CONFIG} = require('../validateThemeConfig');

const {normalizeThemeConfig} = require('@docusaurus/utils-validation');

function testValidateThemeConfig(partialThemeConfig) {
  return normalizeThemeConfig(ThemeConfigSchema, {
    ...DEFAULT_CONFIG,
    ...partialThemeConfig,
  });
}

function testOk(partialThemeConfig) {
  expect(
    testValidateThemeConfig({...DEFAULT_CONFIG, ...partialThemeConfig}),
  ).toEqual({
    ...DEFAULT_CONFIG,
    ...partialThemeConfig,
  });
}

describe('themeConfig', () => {
  test('should accept valid theme config', () => {
    const userConfig = {
      prism: {
        theme: require('prism-react-renderer/themes/github'),
        darkTheme: require('prism-react-renderer/themes/dracula'),
        defaultLanguage: 'javascript',
        additionalLanguages: ['kotlin', 'java'],
      },
      announcementBar: {
        id: 'supportus',
        content: 'pls support',
        backgroundColor: '#fff',
        textColor: '#000',
        isCloseable: true,
      },
      image: 'img/docusaurus-soc.png',
      navbar: {
        style: 'primary',
        hideOnScroll: true,
        title: 'Docusaurus',
        logo: {
          alt: 'Docusaurus Logo',
          src: 'img/docusaurus.svg',
          srcDark: 'img/docusaurus_keytar.svg',
        },
        items: [
          {
            type: 'docsVersionDropdown',
            position: 'left',
            dropdownItemsBefore: [],
            dropdownItemsAfter: [],
          },
          {
            to: 'docs/next/support',
            label: 'Community',
            position: 'left',
            activeBaseRegex: `docs/next/(support|team|resources)`,
            'aria-label': 'Community',
          },
        ],
      },
      footer: {
        style: 'dark',
        links: [
          {
            title: 'Learn',
            items: [
              {
                label: 'Introduction',
                to: 'docs',
              },
            ],
          },
        ],
        logo: {
          alt: 'Facebook Open Source Logo',
          src: 'img/oss_logo.png',
          href: 'https://opensource.facebook.com',
        },
        copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc. Built with Docusaurus.`,
      },
    };
    expect(testValidateThemeConfig(userConfig)).toEqual({
      ...DEFAULT_CONFIG,
      ...userConfig,
    });
  });

  test('should allow possible types of navbar items', () => {
    const config = {
      navbar: {
        items: [
          // Doc link
          {
            type: 'doc',
            position: 'left',
            docId: 'intro',
            label: 'Introduction',
            activeSidebarClassName: 'custom-class',
          },
          // Regular link
          {
            to: '/guide/',
            label: 'Guide',
            position: 'left',
            activeBaseRegex: '/guide/',
          },
          // Regular dropdown
          {
            label: 'Community',
            position: 'right',
            items: [
              {
                label: 'Facebook',
                href: 'https://.facebook.com/',
                target: '_self',
              },
              {
                label: 'GitHub',
                href: 'https://github.com/facebook/docusaurus',
                className: 'github-link',
              },
            ],
          },
          // Doc version dropdown
          {
            type: 'docsVersionDropdown',
            position: 'right',
            dropdownActiveClassDisabled: true,
            dropdownItemsBefore: [
              {
                href:
                  'https://www.npmjs.com/package/docusaurus?activeTab=versions',
                label: 'Versions on npm',
                className: 'npm-styled',
                target: '_self',
              },
            ],
            dropdownItemsAfter: [
              {
                to: '/versions',
                label: 'All versions',
                className: 'all_vers',
              },
            ],
          },
          // External link with custom data attribute
          {
            href: 'https://github.com/facebook/docusaurus',
            position: 'right',
            className: 'header-github-link',
            'aria-label': 'GitHub repository',
          },
          // Docs version
          {
            type: 'docsVersion',
            position: 'left',
            label: 'Current version',
          },
        ],
      },
    };
    expect(testValidateThemeConfig(config)).toEqual({
      ...DEFAULT_CONFIG,
      navbar: {
        ...DEFAULT_CONFIG.navbar,
        ...config.navbar,
      },
    });
  });

  test('should allow empty alt tags for the logo image in the header', () => {
    const altTagConfig = {
      navbar: {
        logo: {
          alt: '',
          src: '/arbitrary-logo.png',
        },
        hideOnScroll: false,
      },
    };
    expect(testValidateThemeConfig(altTagConfig)).toEqual({
      ...DEFAULT_CONFIG,
      navbar: {
        ...DEFAULT_CONFIG.navbar,
        ...altTagConfig.navbar,
      },
    });
  });

  test('should allow empty alt tags for the logo image in the footer', () => {
    const partialConfig = {
      footer: {
        logo: {
          alt: '',
          src: '/arbitrary-logo.png',
        },
      },
    };
    const normalizedConfig = testValidateThemeConfig(partialConfig);

    expect(normalizedConfig).toEqual({
      ...normalizedConfig,
      footer: {
        ...normalizedConfig.footer,
        ...partialConfig.footer,
      },
    });
  });

  test('should accept valid prism config', () => {
    const prismConfig = {
      prism: {
        additionalLanguages: ['kotlin', 'java'],
      },
    };
    expect(testValidateThemeConfig(prismConfig)).toEqual({
      ...DEFAULT_CONFIG,
      ...prismConfig,
    });
  });

  describe('customCss config', () => {
    test('should accept customCss undefined', () => {
      testOk({
        customCss: undefined,
      });
    });

    test('should accept customCss string', () => {
      testOk({
        customCss: './path/to/cssFile.css',
      });
    });

    test('should accept customCss string array', () => {
      testOk({
        customCss: ['./path/to/cssFile.css', './path/to/cssFile2.css'],
      });
    });

    test('should reject customCss number', () => {
      expect(() =>
        testValidateThemeConfig({
          customCss: 42,
        }),
      ).toThrowErrorMatchingInlineSnapshot(
        `"\\"customCss\\" must be one of [array, string]"`,
      );
    });
  });

  describe('color mode config', () => {
    const withDefaultValues = (colorMode) =>
      merge({}, DEFAULT_CONFIG.colorMode, colorMode);

    test('minimal config', () => {
      const colorMode = {
        switchConfig: {
          darkIcon: '🌙',
        },
      };
      expect(testValidateThemeConfig({colorMode})).toEqual({
        ...DEFAULT_CONFIG,
        colorMode: withDefaultValues(colorMode),
      });
    });

    test('max config', () => {
      const colorMode = {
        defaultMode: 'dark',
        disableSwitch: false,
        respectPrefersColorScheme: true,
        switchConfig: {
          darkIcon: '🌙',
          darkIconStyle: {
            marginTop: '1px',
            marginLeft: '2px',
          },
          lightIcon: '☀️',
          lightIconStyle: {
            marginLeft: '1px',
          },
        },
      };
      expect(testValidateThemeConfig({colorMode})).toEqual({
        ...DEFAULT_CONFIG,
        colorMode: withDefaultValues(colorMode),
      });
    });

    test('undefined config', () => {
      const colorMode = undefined;
      expect(testValidateThemeConfig({colorMode})).toEqual({
        ...DEFAULT_CONFIG,
        colorMode: withDefaultValues(colorMode),
      });
    });

    test('empty config', () => {
      const colorMode = {};
      expect(testValidateThemeConfig({colorMode})).toEqual({
        ...DEFAULT_CONFIG,
        colorMode: {
          ...DEFAULT_CONFIG.colorMode,
          ...colorMode,
        },
      });
    });

    test('empty switch config', () => {
      const colorMode = {
        switchConfig: {},
      };
      expect(testValidateThemeConfig({colorMode})).toEqual({
        ...DEFAULT_CONFIG,
        colorMode: withDefaultValues(colorMode),
      });
    });
  });
});
