/**
 * 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 fs from 'fs-extra';
import path from 'path';
import pluginContentBlog from '../index';
import {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';
import {PluginOptionSchema} from '../pluginOptionSchema';
import {PluginOptions, EditUrlFunction} from '../types';
import Joi from 'joi';

function getI18n(locale: string): I18n {
  return {
    currentLocale: locale,
    locales: [locale],
    defaultLocale: locale,
    localeConfigs: {},
  };
}

const DefaultI18N: I18n = getI18n('en');

function validateAndNormalize(
  schema: Joi.ObjectSchema,
  options: Partial<PluginOptions>,
) {
  const {value, error} = schema.validate(options);
  if (error) {
    throw error;
  } else {
    return value;
  }
}

describe('loadBlog', () => {
  const PluginPath = 'blog';

  const BaseEditUrl = 'https://baseEditUrl.com/edit';

  const getBlogPosts = async (
    siteDir: string,
    pluginOptions: Partial<PluginOptions> = {},
    i18n: I18n = DefaultI18N,
  ) => {
    const generatedFilesDir: string = path.resolve(siteDir, '.docusaurus');
    const siteConfig = {
      title: 'Hello',
      baseUrl: '/',
      url: 'https://docusaurus.io',
    } as DocusaurusConfig;
    const plugin = pluginContentBlog(
      {
        siteDir,
        siteConfig,
        generatedFilesDir,
        i18n,
      } as LoadContext,
      validateAndNormalize(PluginOptionSchema, {
        path: PluginPath,
        editUrl: BaseEditUrl,
        ...pluginOptions,
      }),
    );
    const {blogPosts} = (await plugin.loadContent!())!;

    return blogPosts;
  };

  test('simple website', async () => {
    const siteDir = path.join(__dirname, '__fixtures__', 'website');
    const blogPosts = await getBlogPosts(siteDir);

    expect({
      ...blogPosts.find((v) => v.metadata.title === 'date-matter')!.metadata,
      ...{prevItem: undefined},
    }).toEqual({
      editUrl: `${BaseEditUrl}/blog/date-matter.md`,
      permalink: '/blog/date-matter',
      readingTime: 0.02,
      source: path.posix.join('@site', PluginPath, 'date-matter.md'),
      title: 'date-matter',
      description: `date inside front matter`,
      date: new Date('2019-01-01'),
      formattedDate: 'January 1, 2019',
      prevItem: undefined,
      tags: [],
      nextItem: {
        permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash',
        title: 'Happy 1st Birthday Slash! (translated)',
      },
      truncated: false,
    });

    expect(
      blogPosts.find(
        (v) => v.metadata.title === 'Happy 1st Birthday Slash! (translated)',
      )!.metadata,
    ).toEqual({
      editUrl: `${BaseEditUrl}/blog/2018-12-14-Happy-First-Birthday-Slash.md`,
      permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash',
      readingTime: 0.015,
      source: path.posix.join(
        '@site',
        // pluginPath,
        path.posix.join('i18n', 'en', 'docusaurus-plugin-content-blog'),
        '2018-12-14-Happy-First-Birthday-Slash.md',
      ),
      title: 'Happy 1st Birthday Slash! (translated)',
      description: `Happy birthday! (translated)`,
      date: new Date('2018-12-14'),
      formattedDate: 'December 14, 2018',
      tags: [],
      prevItem: {
        permalink: '/blog/date-matter',
        title: 'date-matter',
      },
      truncated: false,
    });

    expect({
      ...blogPosts.find((v) => v.metadata.title === 'Complex Slug')!.metadata,
      ...{prevItem: undefined},
    }).toEqual({
      editUrl: `${BaseEditUrl}/blog/complex-slug.md`,
      permalink: '/blog/hey/my super path/héllô',
      readingTime: 0.015,
      source: path.posix.join('@site', PluginPath, 'complex-slug.md'),
      title: 'Complex Slug',
      description: `complex url slug`,
      prevItem: undefined,
      nextItem: {
        permalink: '/blog/simple/slug',
        title: 'Simple Slug',
      },
      date: new Date('2020-08-16'),
      formattedDate: 'August 16, 2020',
      tags: [],
      truncated: false,
    });

    expect({
      ...blogPosts.find((v) => v.metadata.title === 'Simple Slug')!.metadata,
      ...{prevItem: undefined},
    }).toEqual({
      editUrl: `${BaseEditUrl}/blog/simple-slug.md`,
      permalink: '/blog/simple/slug',
      readingTime: 0.015,
      source: path.posix.join('@site', PluginPath, 'simple-slug.md'),
      title: 'Simple Slug',
      description: `simple url slug`,
      prevItem: undefined,
      nextItem: {
        permalink: '/blog/draft',
        title: 'draft',
      },
      date: new Date('2020-08-15'),
      formattedDate: 'August 15, 2020',
      tags: [],
      truncated: false,
    });
  });

  test('simple website blog dates localized', async () => {
    const siteDir = path.join(__dirname, '__fixtures__', 'website');
    const blogPostsFrench = await getBlogPosts(siteDir, {}, getI18n('fr'));
    expect(blogPostsFrench).toHaveLength(5);
    expect(blogPostsFrench[0].metadata.formattedDate).toMatchInlineSnapshot(
      `"16 août 2020"`,
    );
    expect(blogPostsFrench[1].metadata.formattedDate).toMatchInlineSnapshot(
      `"15 août 2020"`,
    );
    expect(blogPostsFrench[2].metadata.formattedDate).toMatchInlineSnapshot(
      `"27 février 2020"`,
    );
    expect(blogPostsFrench[3].metadata.formattedDate).toMatchInlineSnapshot(
      `"1 janvier 2019"`,
    );
    expect(blogPostsFrench[4].metadata.formattedDate).toMatchInlineSnapshot(
      `"14 décembre 2018"`,
    );
  });

  test('edit url with editLocalizedBlogs true', async () => {
    const siteDir = path.join(__dirname, '__fixtures__', 'website');
    const blogPosts = await getBlogPosts(siteDir, {editLocalizedFiles: true});

    const localizedBlogPost = blogPosts.find(
      (v) => v.metadata.title === 'Happy 1st Birthday Slash! (translated)',
    )!;

    expect(localizedBlogPost.metadata.editUrl).toEqual(
      `${BaseEditUrl}/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md`,
    );
  });

  test('edit url with editUrl function', async () => {
    const siteDir = path.join(__dirname, '__fixtures__', 'website');

    const hardcodedEditUrl = 'hardcoded-edit-url';
    const editUrlFunction: EditUrlFunction = jest.fn(() => hardcodedEditUrl);

    const blogPosts = await getBlogPosts(siteDir, {editUrl: editUrlFunction});

    blogPosts.forEach((blogPost) => {
      expect(blogPost.metadata.editUrl).toEqual(hardcodedEditUrl);
    });

    expect(editUrlFunction).toHaveBeenCalledTimes(5);
    expect(editUrlFunction).toHaveBeenCalledWith({
      blogDirPath: 'blog',
      blogPath: 'date-matter.md',
      permalink: '/blog/date-matter',
      locale: 'en',
    });
    expect(editUrlFunction).toHaveBeenCalledWith({
      blogDirPath: 'blog',
      blogPath: 'draft.md',
      permalink: '/blog/draft',
      locale: 'en',
    });
    expect(editUrlFunction).toHaveBeenCalledWith({
      blogDirPath: 'blog',
      blogPath: 'complex-slug.md',
      permalink: '/blog/hey/my super path/héllô',
      locale: 'en',
    });
    expect(editUrlFunction).toHaveBeenCalledWith({
      blogDirPath: 'blog',
      blogPath: 'simple-slug.md',
      permalink: '/blog/simple/slug',
      locale: 'en',
    });
    expect(editUrlFunction).toHaveBeenCalledWith({
      blogDirPath: 'i18n/en/docusaurus-plugin-content-blog',
      blogPath: '2018-12-14-Happy-First-Birthday-Slash.md',
      permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash',
      locale: 'en',
    });
  });

  test('draft blog post not exists in production build', async () => {
    process.env.NODE_ENV = 'production';
    const siteDir = path.join(__dirname, '__fixtures__', 'website');
    const blogPosts = await getBlogPosts(siteDir);

    expect(blogPosts.find((v) => v.metadata.title === 'draft')).toBeUndefined();
  });

  test('create blog post without date', async () => {
    const siteDir = path.join(
      __dirname,
      '__fixtures__',
      'website-blog-without-date',
    );
    const blogPosts = await getBlogPosts(siteDir);
    const noDateSource = path.posix.join('@site', PluginPath, 'no date.md');
    const noDateSourceBirthTime = (
      await fs.stat(noDateSource.replace('@site', siteDir))
    ).birthtime;
    const formattedDate = Intl.DateTimeFormat('en', {
      day: 'numeric',
      month: 'long',
      year: 'numeric',
    }).format(noDateSourceBirthTime);

    expect({
      ...blogPosts.find((v) => v.metadata.title === 'no date')!.metadata,
      ...{prevItem: undefined},
    }).toEqual({
      editUrl: `${BaseEditUrl}/blog/no date.md`,
      permalink: '/blog/no date',
      readingTime: 0.01,
      source: noDateSource,
      title: 'no date',
      description: `no date`,
      date: noDateSourceBirthTime,
      formattedDate,
      tags: [],
      prevItem: undefined,
      nextItem: undefined,
      truncated: false,
    });
  });
});
