/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable prefer-destructuring */
/* eslint-disable no-unused-vars */
/* eslint no-console: ["error", { allow: ["log"] }], no-shadow: ["error", { "allow": ["marketSections", "prefilledModules"] }] */
/* eslint-disable dot-notation */

import loadash from 'lodash/index.js';
import chalk from 'chalk';
import fs from 'fs';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { getData, getLocalData } from './src/helpers/api.mjs';

import { generateTrackerLink } from './src/helpers/generators.mjs';
import processor, { processSitemapPages } from './src/helpers/processor/index.mjs';
import { pickAuthorsPageKeys } from './src/constants/pick-keys.mjs';
import settings from './src/constants/settings.mjs';
import { translate } from './src/helpers/getters.mjs';
import { groupBy } from './src/helpers/processor/common.mjs';

const __dirname = dirname(fileURLToPath(import.meta.url));
const { cloneDeep, chunk, pick } = loadash;

const isPreview = process.env.GATSBY_PREVIEW_MODE === 'true';
const appName = isPreview ? '/src/components/app-preview.js' : '/src/components/app.js';

let preconnectLinks = null;
let pages = null;
let htmlSitemapPages = null;
let marketSections = [];
let allMarketSections = null;
let prefilledModules = [];
let siteInfo = null;
let operators = null;
let allMarkets = null;
let translations = null;
let allTranslations = null;
let languageKey = null;
let context404 = null;
let sports = null;
let siteSchema = null;
let templates = null;
let authors = null;

function createArchivePage(pageObject, marketSections, prefilledModules, createPage) {
  const archiveModuleIndex = pageObject.sections.main.modules.findIndex(
    (module) => module.name === 'archive'
  );
  const archiveModule = pageObject.sections.main.modules[archiveModuleIndex];
  let archivePages = cloneDeep(pages[pageObject.market][archiveModule.model_type]);

  if (process.env.CUSTOM_CONTENT_PAGES_PATH && archivePages) {
    // eslint-disable-next-line array-callback-return
    archivePages = archivePages.filter((item) => {
      if (item.path.includes(process.env.CUSTOM_CONTENT_PAGES_PATH)) {
        return item;
      }
    });
  }
  if (!archivePages) {
    console.log(`Archive for ${pageObject.path} broken`);
  }

  if (archiveModule.pagination_type !== 'load_more') {
    const numOfColumns = archiveModule.desktop_num_of_columns;
    const calDefaultNrOfItems = (numOfColumns !== null ? numOfColumns : 4) * 3;
    const numOfItemsPerPage = Math.sign(archiveModule.num_of_items)
      ? archiveModule.num_of_items
      : calDefaultNrOfItems;
    const chunked = archivePages && chunk(cloneDeep(archivePages), numOfItemsPerPage);

    if (chunked) {
      chunked.forEach((value, index) => {
        const page = cloneDeep(pageObject);
        page.hasArchive = true;
        const numOfPages = chunked.length;
        const archive = cloneDeep(page.sections.main.modules[archiveModuleIndex]);
        archive.currentPage = 1 + index; // 0 skip 0
        archive.numOfPages = numOfPages;
        archive.rootPath =
          pageObject.path.charAt(0) !== '/' ? `/${pageObject.path}` : pageObject.path;
        archive.items = value.map((item) => processor.clonePage(item));
        switch (archive.currentPage) {
          case 1:
            page.path = pageObject.path;
            break;
          default:
            page.path = `${pageObject.path}/${translate(
              translations,
              'archive_page_path',
              'page'
            )}/${archive.currentPage}`;
            page.meta_title += translate(
              translations,
              'archive_title_suffix',
              '- Page [number]'
            ).replace('[number]', archive.currentPage);
            page.meta_description += translate(
              translations,
              'archive_description_suffix',
              '- Page [number]'
            ).replace('[number]', archive.currentPage);
            break;
        }
        page.sections.main.modules[archiveModuleIndex] = archive;

        createPage({
          path: page.path,
          component: `${__dirname}${appName}`,
          context: { page, marketSections, prefilledModules, siteInfo, translations, allMarkets },
        });
      });
    } else {
      const page = cloneDeep(pageObject);
      page.hasArchive = true;
      createPage({
        path: page.path,
        component: `${__dirname}${appName}`,
        context: { page, marketSections, prefilledModules, siteInfo, translations, allMarkets },
      });
    }
  } else {
    const page = cloneDeep(pageObject);
    const archive = cloneDeep(page.sections.main.modules[archiveModuleIndex]);
    archive.items = cloneDeep(archivePages).map((item) => processor.clonePage(item));

    page.sections.main.modules[archiveModuleIndex] = archive;
    createPage({
      path: page.path,
      component: `${__dirname}${appName}`,
      context: { page, marketSections, prefilledModules, siteInfo, translations, allMarkets },
    });
  }
}

function hasArchiveModule(page) {
  if (!page.sections) return false;
  return Object.keys(page.sections).find((sectionKey) => {
    if (!page.sections[sectionKey] || !page.sections[sectionKey].modules) return false;
    return page.sections[sectionKey].modules.find((module) => module.name === 'archive');
  });
}

// eslint-disable-next-line import/prefer-default-export
export const createPages = async ({ actions: { createPage } }, themeOptions) => {
  process.env.GATSBY_SITE_NAME = String(themeOptions.siteName);
  if (process.env.GATSBY_PREVIEW_MODE === 'true') {
    console.log(chalk.magenta('info') + chalk.whiteBright(' preview mode enabled'));
    createPage({
      path: '/',
      component: `${__dirname}${appName}`,
      context: {
        page: { relation_type: 'page' },
        preview: true,
        siteInfo,
        ...themeOptions,
      },
    });
    return;
  }

  let response = [];
  if (process.env.LOCAL_DATA === 'false') {
    console.log(chalk.magenta('info') + chalk.whiteBright(' getting data from api'));
    response = await getData(String(themeOptions.siteName));
  } else {
    console.log(chalk.magenta('info') + chalk.whiteBright(' getting data from local file'));
    response = await getLocalData(fs);
  }

  const stream = fs.createWriteStream('rewrites.conf');
  console.log(chalk.magenta('info') + chalk.whiteBright(' creating rewrite rules'));
  if (response.redirects) {
    response.redirects.forEach((redirect) => {
      if (![301, 302, 410].includes(parseInt(redirect.code))) return;
      if ([301, 302].includes(parseInt(redirect.code))) {
        const redirectName = parseInt(redirect.code) === 301 ? 'permanent' : 'redirect';
        stream.write(
          `rewrite (?i)^${redirect.from}/?$ ${redirect.to.replace(/[{}]/g, '')} ${redirectName}; \n`
        );
      }
      if (parseInt(redirect.code) === 410) {
        stream.write(`location ~ /${redirect.from} { return 410; } \n`);
      }
    });
  }
  stream.end();

  preconnectLinks = themeOptions.preconnectLinks || [];
  console.log(chalk.magenta('info') + chalk.whiteBright(' starting processor'));

  // add data to modules
  const processed = processor.run(response, themeOptions, fs);
  pages = processed.pages;
  siteInfo = processed.general;
  operators = processed.relations.operator;
  templates = processed.templates;
  // eslint-disable-next-line prefer-destructuring
  languageKey = Object.keys(processed.relations.translations)[0];
  translations = processed.relations.translations[languageKey];
  allTranslations = processed.relations.translations;
  allMarkets = processed.site_markets;
  allMarketSections = processed.market_sections;
  htmlSitemapPages = processSitemapPages(pages, processed.site_markets);

  if (['rage_seo', 'rage_ppc', 'sports'].includes(response.general.type)) {
    sports = Object.keys(response.relations['sports_data'].sports).map(
      (key) => response.relations['sports_data'].sports[key]
    );
  }

  // create robots.txt file
  const robotsTxtContent = siteInfo.robots_txt ? siteInfo.robots_txt : '';
  const streamRobotsTxt = fs.createWriteStream('./static/robots.txt');
  console.log(chalk.magenta('info') + chalk.whiteBright(' creating robots.txt file'));
  streamRobotsTxt.write(robotsTxtContent);
  streamRobotsTxt.end();

  // create every single page
  Object.keys(processed.site_markets).forEach((siteMarket) => {
    if (!processed.pages[siteMarket]['page']) processed.pages[siteMarket]['page'] = [];
    processed.pages[siteMarket]['page'].push({
      meta_title: 'Preview',
      relation_type: 'page',
      path: 'preview',
      template: 'default',
      meta_robots: ['noindex', 'nofollow'],
      sections: {
        main: { modules: [] },
        navigation: { modules: [] },
        sidebar: { modules: [] },
        footer: { modules: [] },
      },
    });
    Object.keys(processed.pages[siteMarket]).forEach((pageType) => {
      processed.pages[siteMarket][pageType].forEach((page) => {
        marketSections = processed.market_sections[siteMarket];
        prefilledModules = processed.prefilled_market_modules[siteMarket];

        const processedPage = page;
        processedPage.preconnect_links = preconnectLinks;

        siteSchema =
          page.path === 'preview'
            ? (page.siteSchema = Object.values(response.schema || {})[0])
            : response.schema[page['market_id']];
        authors = response.authors;

        page.translations = {};
        // siteInfo, siteSchema and authors are added to page for schemaGenerator()
        page.siteInfo = siteInfo;
        page.siteSchema = siteSchema;
        page.authors = Object.keys(authors || {}).map((key) =>
          pick(authors[key], pickAuthorsPageKeys)
        );

        if (hasArchiveModule(page)) {
          createArchivePage(page, marketSections, prefilledModules, createPage);
          return;
        }

        if (page.relation_type === 'event' && !page.relation.event) {
          return;
        }

        const template = templates[page.template_id];
        const autogenerated = template && template.autogenerated_content;
        const contextData = {
          page,
          allMarkets,
          marketSections,
          prefilledModules,
          siteInfo,
          autogenerated,
          siteSchema,
          translations: processed.relations.translations[page.language],
          authors,
          ...themeOptions,
        };

        const pathPrefix = processed.site_markets[siteMarket].path_prefix
          ? `${processed.site_markets[siteMarket].path_prefix}/`
          : null;

        if (page.path === '404') {
          context404 = contextData;
        } else if (
          page.path ===
          `${pathPrefix || ''}${translate(contextData.translations, 'sitemap', 'sitemap')}`
        ) {
          createPage({
            path: `/${page.path}`,
            component: `${__dirname}/src/components/app.js`,
            context: {
              ...contextData,
              sitemapData: { ...htmlSitemapPages[page.market] },
              templates,
            },
          });
        } else {
          const component =
          settings.app_ssr.includes(page.template)
              ? `${__dirname}/src/components/app-ssr.js`
              : `${__dirname}/src/components/app.js`;

          createPage({
            path: page.path.charAt(0) === '/' ? page.path : `/${page.path}`,
            component,
            context: {
              ...contextData,
              isPreview: page.path === 'preview',
            },
          });
        }
      });
    });
  });

  // Generating Affiliate Tracker Link
  const pageTemplate = 'tracker';
  if (['rage_seo', 'rage_ppc'].includes(response.general.type)) {
    Object.keys(
      (processed.relations &&
        processed.relations.sports_data &&
        processed.relations.sports_data.providers) ||
        {}
    ).forEach((providerId) => {
      const provider = processed.relations.sports_data.providers[providerId];
      const tracker = generateTrackerLink(provider, 'main', true, pageTemplate);
      const trackerPageObject = {
        meta_title: 'Tracker',
        template: pageTemplate,
        title: 'Tracker',
        relation_type: 'page',
        language: languageKey,
        path: tracker,
        meta_robots: ['noindex', 'nofollow'],
      };
      createPage({
        path: tracker,
        component: `${__dirname}/src/components/app.js`,
        context: {
          page: trackerPageObject,
          siteInfo,
          provider,
          isTracker: true,
          isLiveStreamProvider: true,
          meta_robots: ['noindex', 'nofollow'],
        },
      });
    });
  }

  // Creating Tracking links
  if (process.env.GEO_TRACKING) {
    const operatorsShortName = groupBy(operators, 'short_name');
    const trackerNames = [];
    Object.keys(operatorsShortName).forEach((shortname) => {
      const operatorsAllMarket = operatorsShortName[shortname];

      Object.keys(operatorsAllMarket).forEach((operator) => {
        Object.keys(operatorsAllMarket[operator].links).forEach((link) => {
          if (!trackerNames.includes(link)) {
            trackerNames.push(link);
          }
        });
      });

      const operatorsByType = groupBy(operatorsAllMarket, 'type');

      Object.keys(operatorsByType).forEach((type) => {
        const operatorsByMarket = groupBy(operatorsByType[type], 'market');
        console.log(trackerNames);

        trackerNames.forEach((link) => {
          const trackerLinkPath = generateTrackerLink(
            operatorsByType[type][0],
            link,
            false,
            pageTemplate
          )
            .toLowerCase()
            .replace(' ', '_');
          console.log(trackerLinkPath);
          const trackerPageObject = {
            meta_title: 'Tracker',
            template: pageTemplate,
            title: 'Tracker',
            relation_type: 'page',
            language: languageKey,
            path: trackerLinkPath,
            meta_robots: ['noindex', 'nofollow'],
          };
          createPage({
            path: trackerLinkPath,
            component: `${__dirname}/src/components/pages/tracker-geo/index.js`,
            context: {
              page: trackerPageObject,
              siteInfo,
              operatorsByMarket,
              isTrackeGeo: true,
              isLiveStreamProvider: false,
            },
          });
        });
      });
    });
  } else {
    Object.keys(operators || {}).forEach((operatorId) => {
      const operator = operators[operatorId];
      const trackerLinks = Object.keys(operator.links);
      const tracker = trackerLinks.map((key) =>
        operator.links[key]
          ? generateTrackerLink(operator, key, false, pageTemplate).toLowerCase().replace(' ', '_')
          : null
      );
      const marketOperator = operator.market.match(/_(\w+)/)[1];

      const trackerComp =
        process.env.IS_TRACKING_SSR === 'true'
          ? `${__dirname}/src/components/pages/tracker/index-ssr.js`
          : `${__dirname}/src/components/pages/tracker/index.js`;

      tracker.forEach((trackerPath) => {
        // Create splash page
        if (trackerPath) {
          const trackerPageObject = {
            meta_title: 'Tracker',
            template: pageTemplate,
            title: 'Tracker',
            relation_type: 'page',
            language: languageKey,
            path: trackerPath,
            meta_robots: ['noindex', 'nofollow'],
          };
          createPage({
            path: trackerPath,
            component: trackerComp,
            context: {
              page: trackerPageObject,
              translations: processed.relations.translations[marketOperator],
              siteInfo,
              operator,
              isTracker: true,
              isLiveStreamProvider: false,
            },
          });
        }
      });
    });
  }
};

export const onCreatePage = ({ page, actions }) => {
  const { createPage, deletePage } = actions;
  if (page.path.match(/^\/[a-z]{2}\/404\/?$/)) {
    const oldPage = { ...page };
    const langCode = page.path.split(`/`)[1];
    page.matchPath = `/${langCode}/*`;
    const marketCode = Object.keys(allMarkets).find(
      (key) => allMarkets[key].path_prefix === langCode
    );
    if (marketCode) {
      // Recreate the modified page
      deletePage(oldPage);
      createPage({
        ...page,
        context: {
          ...context404,
          page: { ...context404.page, market: marketCode, language: langCode },
          marketSections: allMarketSections[marketCode],
          translations: allTranslations[langCode],
        },
        component: `${__dirname}/src/components/app.js`,
      });
    } else {
      deletePage(oldPage);
    }
  } else if (page.path.includes('404')) {
    createPage({
      path: page.path,
      component: `${__dirname}/src/components/app.js`,
      context: context404,
    });
  } else {
    createPage({
      path: page.path,
      component: `${__dirname}${appName}`,
      context: { page, marketSections, prefilledModules, siteInfo },
    });
  }
};

export const onCreateWebpackConfig = ({ actions, stage, getConfig }) => {
  if (stage === 'build-javascript') {
    const config = getConfig();
    // Get the mini-css-extract-plugin
    const miniCssExtractPlugin = config.plugins.find(
      (plugin) => plugin.constructor.name === 'MiniCssExtractPlugin'
    );
    // Set the option here to true.
    if (miniCssExtractPlugin) {
      miniCssExtractPlugin.options.ignoreOrder = true;
    }
    // Update the config.
    actions.replaceWebpackConfig(config);
  }

  actions.setWebpackConfig({
    resolve: {
      alias: {
        '~atoms': `${__dirname}/src/components/atoms`,
        '~molecules': `${__dirname}/src/components/molecules`,
        '~organisms': `${__dirname}/src/components/organisms`,
        '~pages': `${__dirname}/src/components/pages`,
        '~helpers': `${__dirname}/src/helpers`,
        '~hooks': `${__dirname}/src/hooks`,
        '~tests': `${__dirname}/tests`,
        '~context': `${__dirname}/src/context`,
        '~constants': `${__dirname}/src/constants`,
      },
    },
  });
};
