import express from 'express';
import { readFile, existsSync } from 'fs-extra';
import { hbsRenderString } from '@knapsack/core';
import { join, dirname } from 'path';
import { apiUrlBase } from '../lib/constants';
import { createDemoUrl } from '../lib/routes';
import { KnapsackConfig } from '../schemas/knapsack-config';

const router = express.Router();

export function setupRoutes({
  patterns,
  knapsackDistDir,
  distDir,
  publicDir,
  cacheDir,
  plugins,
}: {
  patterns: import('./patterns').Patterns;
  knapsackDistDir: string;
  distDir?: string;
  publicDir?: string;
  cacheDir: string;
  plugins: KnapsackConfig['plugins'];
}): typeof router {
  router.use('*', async (req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header(
      'Access-Control-Allow-Headers',
      'Origin, X-Requested-With, Content-Type, Accept',
    );
    next();
  });

  router.use(`${apiUrlBase}`, (req, res, next) => {
    if (process.env.NODE_ENV === 'production') {
      next();
    } else {
      // faking a slight delay in local development to better reflect re-world delays
      setTimeout(next, 500);
    }
  });

  router.use(
    express.static(knapsackDistDir, {
      maxAge: '1d',
    }),
  );

  const designSystemDistDir = dirname(
    require.resolve('@knapsack/design-system'),
  );
  router.use('/ks-design-system', express.static(designSystemDistDir));

  if (distDir) {
    router.use(
      express.static(distDir, {
        maxAge: '1d',
      }),
    );
  }

  if (cacheDir) {
    router.use(
      express.static(cacheDir, {
        maxAge: '1d',
      }),
    );
  }

  if (publicDir) {
    router.use(express.static(publicDir));
  }

  if (plugins) {
    plugins
      .filter(p => p.publicDir)
      .forEach(plugin => {
        router.use(`/plugins/${plugin.id}`, express.static(plugin.publicDir));
      });
  }

  function getDemoUrls(): {
    id: string;
    title: string;
    templates: {
      id: string;
      title: string;
      demoUrls: string[];
    }[];
  }[] {
    return patterns.getPatterns().map(pattern => {
      return {
        id: pattern.id,
        title: pattern.title,
        templates: pattern.templates.map(template => {
          return {
            id: template.id,
            title: template.title ?? template.id,
            demoUrls: [
              ...template.demos.map(demoId =>
                createDemoUrl({
                  patternId: pattern.id,
                  templateId: template.id,
                  demoId,
                  wrapHtml: true,
                  isInIframe: false,
                }),
              ),
            ],
          };
        }),
      };
    });
  }

  router.get('/demo-urls-data', (req, res) => {
    res.send(getDemoUrls());
  });

  const demoUrlsHbsPath = join(__dirname, './templates/demo-urls.html.hbs');
  if (!existsSync(demoUrlsHbsPath)) {
    throw new Error(
      `Demo URLs handlebars template does not exist: ${demoUrlsHbsPath}`,
    );
  }

  // This page is mainly so IE can get a list of links to view the individual templates outside of the system
  router.route('/demo-urls').get(async (req, res) => {
    const patternDemos = getDemoUrls();
    const demoUrlsHbs = await readFile(demoUrlsHbsPath, 'utf-8');
    const result = hbsRenderString({
      hbsString: demoUrlsHbs,
      data: {
        patternDemos,
      },
    });

    res.send(result);
  });

  // Since this is a Single Page App, we will send all html requests to the `index.html` file in the dist
  router.use('*', (req, res, next) => {
    const { accept = '' } = req.headers;
    const accepted = accept.split(',');
    // this is for serving up a Netlify CMS folder if present
    if (accepted.includes('text/html')) {
      res.sendFile(join(knapsackDistDir, 'index.html'));
    } else {
      next();
    }
  });

  return router;
}
