import commandLineArgs from 'command-line-args';
import pause from 'connect-pause';
import jsonServer from 'json-server';

const optionDefinitions = [
  {
    name: 'delay',
    description: 'Add a delay in ms to the server. Defaults to 200.',
    alias: 'd',
    type: Number,
    defaultValue: 200,
  },
];

const options = commandLineArgs(optionDefinitions);

const server = jsonServer.create();
const router = jsonServer.router('api.json');
const middlewares = jsonServer.defaults();

server.use(pause(options.delay));
server.use(middlewares);

server.use(
  jsonServer.rewriter({
    '/api/*': '/$1',
    '*sort=utforandeVerksamhet*': '$1sort=utforandeVerksamhet[0]$2',
    '*sort=tjanst*': '$1sort=tjanst[0]$2',
    '/users/invite*': '/invites$1',
    '/employees*search=*': '/employees$1fullName_like=$2',
    '/employees*onlyEmployeesWithoutAuthorization=*': '/employees$1roles.length_lte=1',
    '/employees*': '/employees$1',
    '/services*': '/tjanster$1',
    '/participants': '/participants?_embed=employees',
    '/participant/:id': '/participants/:id?_embed=employees',
    '/auth/userinfo': '/userinfo',
    '/auth/organizations': '/organizations',
    '/users/currentUser': '/currentUser',
    '/users*': '/employees$1',
    '/avrop/tjanster*': '/avropTjanster$1',
    '/avrop/handledare*': '/handledare$1',
    '/avrop/utforandeverksamheter*': '/utforandeVerksamheter$1',
    '/avrop/kommuner*': '/kommuner$1',
    '/avrop*utforandeverksamhetId*': '/avrop$1utforandeVerksamhetId$2',
    '/deltagare*onlyMyDeltagare=*': '/minaDeltagare',
    '/avrop*tjanstKod*': '/avrop$1tjanstekod$2',
    '/deltagare?*': '/avrop?$1',
    '/deltagare/:sokandeId/avrop': '/avrop?sokandeId=:sokandeId',
    '/deltagare/:sokandeId/*': '/deltagare/:sokandeId',
    '*page=*': '$1_page=$2',
    '*limit=*': '$1_limit=$2',
    '*sort=*': '$1_sort=$2',
    '*order=*': '$1_order=$2',
    '/auth/token?accessCode=auth_code_from_CIAM_with_all_permissions': '/getTokenFullAccess',
  })
);

router.render = (req, res) => {
  const method = req.originalMethod;
  const parsedUrl = method === 'GET' ? req._parsedOriginalUrl : req._parsedUrl;
  const pathname = parsedUrl.pathname;
  const params = parsedUrl.query ? new URLSearchParams(parsedUrl.query) : null;
  const requestHeaders = req.headers;

  // all paths except /auth/token requires Authorization header.
  if (!pathname.includes('/auth/token') && !requestHeaders.authorization) {
    return res.status(401).jsonp({ error: 'No valid access-token' });
  }

  if (method === 'PATCH') {
    if (pathname === '/handledare/assign') {
      // Returning status 204 as this is the same as in the API, BUT we're not actually updating the mock-api
      return res.status(204).jsonp();
    }
    if (pathname === '/invites' && req.body?.emails) {
      return res.status(200).jsonp({
        data: {
          invitedUsers: req.body.emails,
          assignedUsers: [],
          existingUsersInCurrentOrg: [],
          failedInvite: [],
          alreadyInvitedUsers: [],
        },
      });
    }
  }

  // Return custom error when status is 404.
  if (res.statusCode === 404) {
    return res.status(404).jsonp({ error: `Can't find path: ${pathname}` });
  }

  // Add createdAt to the body
  if (method === 'POST') {
    req.body.createdAt = Date.now();
  }

  let data = res.locals.data;
  const deltagareRegex = /(?:\/deltagare\/)(?:\d*\/)(contact|driverlicense|educationlevels\/highest|educations|translator|work\/disabilities|work\/languages|work\/experiences)/g;
  const isDeltagarePath = deltagareRegex.exec(pathname);
  const avropRegex = /(?:\/avrop\/(?:tjanster|utforandeverksamheter|kommuner|\d))|(?:\/deltagare\/\d\/(avrop))/g;
  const isAvropPath = avropRegex.exec(pathname);

  if (isDeltagarePath) {
    const deltagareSubPath = getDeltagareSubPath(isDeltagarePath[1]);
    data = res.locals.data[deltagareSubPath] || {};
  }
  if (isAvropPath) {
    if (params) {
      const newData = [];
      params.forEach((value, key) => {
        newData.push(
          ...data.filter(item => {
            return item[`related_${key}`].includes(value);
          })
        );
      });

      data = newData.filter((value, index, arr) => arr.findIndex(item => item.code === value.code) === index);
    } else if (isAvropPath[1]) {
      data = data[0];
    }
  }

  if (pathname === '/deltagare') {
    // NOTE: this is reading from avrop.js
    data = data.map(
      ({
        sokandeId,
        fornamn,
        efternamn,
        tjansteNamn,
        utforandeverksamhet,
        adress,
        startdatumAvrop,
        slutdatumAvrop,
        hasAvbrott,
        genomforandeReferens,
      }) => ({
        sokandeId: sokandeId.toString(),
        fornamn,
        efternamn,
        tjanst: tjansteNamn,
        utforandeVerksamhet: utforandeverksamhet,
        utforandeAdress: adress,
        startdatumAvrop,
        slutdatumAvrop,
        hasAvbrott,
        genomforandeReferens,
      })
    );
  }

  res.jsonp({
    data,
    ...appendMetaData(params, res),
  });
};

server.use(router);
server.listen(8000, () => {
  console.info('JSON Server is running');
});

function appendMetaData(params, res) {
  if (params && params.has('page')) {
    const limit = +params.get('limit');
    const page = +params.get('page');
    const count = res.get('X-Total-Count');
    const totalPage = Math.ceil(count / limit);
    return {
      meta: {
        count,
        limit,
        page,
        totalPage,
      },
    };
  }

  return null;
}

function getDeltagareSubPath(path) {
  switch (path) {
    case 'educationlevels/highest':
      return 'highestEducation';
    case 'work/disabilities':
      return 'disabilities';
    case 'work/languages':
      return 'workLanguages';
    case 'work/experiences':
      return 'workExperiences';
    default:
      return path;
  }
}
