/**
 * This is the router config, which defined the location for
 * each page within the app, and how they should be loaded
 * Note that the page paths are defined in @/utils/defaults.js
 */

// Import Vue.js and vue router
import Vue from 'vue';
import Router from 'vue-router';
import { Progress } from 'rsup-progress';

// Import views, that are not lazy-loaded
import Home from '@/views/Home.vue';

// Import helper functions, config data and defaults
import { isAuthEnabled, isLoggedIn, isGuestAccessEnabled } from '@/utils/Auth';
import { makePageSlug, makePageName } from '@/utils/ConfigHelpers';
import { metaTagData, startingView, routePaths } from '@/utils/defaults';
import ErrorHandler from '@/utils/ErrorHandler';

// Import data from users conf file. Note that rebuild is required for this to update.
import conf from '../public/conf.yml';

if (!conf) {
  ErrorHandler('You\'ve not got any data in your config file yet.');
}

// Assign top-level config fields, check not null
const config = conf || {};
const pages = config.pages || [];
const pageInfo = config.pageInfo || {};
const appConfig = config.appConfig || {};

Vue.use(Router);
const progress = new Progress({ color: 'var(--progress-bar)' });

/* Returns true if user is already authenticated, or if auth is not enabled */
const isAuthenticated = () => {
  const authEnabled = isAuthEnabled();
  const userLoggedIn = isLoggedIn();
  const guestEnabled = isGuestAccessEnabled();
  return (!authEnabled || userLoggedIn || guestEnabled);
};

/* Get the users chosen starting view from app config, or return default */
const getStartingView = () => appConfig.startingView || startingView;

/**
 * Returns the component that should be rendered at the base path,
 * Defaults to Home, but the user can change this to Workspace of Minimal
 */
const getStartingComponent = () => {
  const usersPreference = getStartingView();
  switch (usersPreference) {
    case 'minimal': return () => import('./views/Minimal.vue');
    case 'workspace': return () => import('./views/Workspace.vue');
    default: return Home;
  }
};

/* Returns the meta tags for each route */
const makeMetaTags = (defaultTitle) => ({
  title: pageInfo.title || defaultTitle,
  metaTags: metaTagData,
});

const makeSubConfigPath = (rawPath) => {
  if (!rawPath) return '';
  if (rawPath.startsWith('/') || rawPath.startsWith('http')) return rawPath;
  else return `/${rawPath}`;
};

/* For each additional config file, create routes for home, minimal and workspace views */
const makeMultiPageRoutes = (userPages) => {
  // If no multi pages specified, or is not array, then return nothing
  if (!userPages || !Array.isArray(userPages)) return [];
  const multiPageRoutes = [];
  // For each user page, create an additional route
  userPages.forEach((page) => {
    if (!page.name || !page.path) { // Sumin not right, show warning
      ErrorHandler('Additional pages must have both a `name` and `path`');
    }
    // Props to be passed to home mixin
    const subPageInfo = {
      subPageInfo: {
        confPath: makeSubConfigPath(page.path),
        pageId: makePageName(page.name),
        pageTitle: page.name,
      },
    };
    // Create route for default homepage
    multiPageRoutes.push({
      path: makePageSlug(page.name, 'home'),
      name: `${subPageInfo.subPageInfo.pageId}-home`,
      component: Home,
      props: subPageInfo,
    });
    // Create route for the workspace view
    multiPageRoutes.push({
      path: makePageSlug(page.name, 'workspace'),
      name: `${subPageInfo.subPageInfo.pageId}-workspace`,
      component: () => import('./views/Workspace.vue'),
      props: subPageInfo,
    });
    // Create route for the minimal view
    multiPageRoutes.push({
      path: makePageSlug(page.name, 'minimal'),
      name: `${subPageInfo.subPageInfo.pageId}-minimal`,
      component: () => import('./views/Minimal.vue'),
      props: subPageInfo,
    });
  });
  return multiPageRoutes;
};

/* Routing mode, can be either 'hash', 'history' or 'abstract' */
const mode = appConfig.routingMode || 'history';

/* List of all routes, props, components and metadata */
const router = new Router({
  mode,
  routes: [
    ...makeMultiPageRoutes(pages),
    { // The default view can be customized by the user
      path: '/',
      name: `landing-page-${getStartingView()}`,
      component: getStartingComponent(),
      meta: makeMetaTags('Home Page'),
    },
    { // Default home page
      path: routePaths.home,
      name: 'home',
      component: Home,
      meta: makeMetaTags('Home Page'),
    },
    { // View only single section
      path: `${routePaths.home}/:section`,
      name: 'home-section',
      component: Home,
      meta: makeMetaTags('Home Page'),
    },
    { // Workspace view page
      path: routePaths.workspace,
      name: 'workspace',
      component: () => import('./views/Workspace.vue'),
      meta: makeMetaTags('Workspace'),
    },
    { // Minimal view page
      path: routePaths.minimal,
      name: 'minimal',
      component: () => import('./views/Minimal.vue'),
      meta: makeMetaTags('Start Page'),
    },
    { // The login page
      path: routePaths.login,
      name: 'login',
      component: () => import('./views/Login.vue'),
      beforeEnter: (to, from, next) => {
        // If the user already logged in + guest mode not enabled, then redirect home
        if (isAuthenticated() && !isGuestAccessEnabled()) router.push({ path: '/' });
        next();
      },
    },
    { // The about app page
      path: routePaths.about,
      name: 'about', // We lazy load the About page so as to not slow down the app
      component: () => import('./views/About.vue'),
      meta: makeMetaTags('About Dashy'),
    },
    { // The export config page
      path: routePaths.download,
      name: 'download',
      component: () => import('./views/DownloadConfig.vue'),
      meta: makeMetaTags('Download Config'),
    },
    { // Page not found, any non-defined routes will land here
      path: routePaths.notFound,
      name: '404',
      component: () => import('./views/404.vue'),
      meta: makeMetaTags('404 Not Found'),
      beforeEnter: (to, from, next) => {
        if (to.redirectedFrom) { // Log error, if redirected here from another route
          ErrorHandler(`Route not found: '${to.redirectedFrom}'`);
        }
        next();
      },
    },
    { // Redirect any not-found routed to the 404 view
      path: '*',
      redirect: '/404',
    },
  ],
});

/**
 * Before loading a route, check if the user has authentication enabled
 * if so, then ensure that they are correctly logged in as a valid user
 * If not logged in, prevent all access and redirect them to login page
 * */
router.beforeEach((to, from, next) => {
  progress.start();
  if (to.name !== 'login' && !isAuthenticated()) next({ name: 'login' });
  else next();
});

/* If title is missing, then apply default page title */
router.afterEach((to) => {
  progress.end();
  Vue.nextTick(() => {
    document.title = to.meta.title || 'Dashy';
  });
});

// All done - export the now configured router
export default router;
