// admin/service-node.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0

'use strict';

const express = require('express');

const { SiteController, SiteError } = require('../../../lib/site-lib');

class ServiceNodeController extends SiteController {

  constructor (dtp) {
    super(dtp, module.exports);
  }

  async start ( ) {
    const router = express.Router();
    router.use(async (req, res, next) => {
      res.locals.currentView = 'admin';
      res.locals.adminView = 'service-node';
      return next();
    });

    router.param('clientId', this.populateClientId.bind(this));
    router.param('connectRequestId', this.populateConnectRequestId.bind(this));

    router.post('/connect-queue/:connectRequestId', this.postConnectRequestResponse.bind(this));
    router.post('/:clientId', this.postClientUpdate.bind(this));

    router.get('/connect-queue', this.getServiceNodeConnectQueue.bind(this));
    router.get('/:clientId', this.getClientView.bind(this));
    router.get('/', this.getIndex.bind(this));

    router.delete('/:clientId', this.deleteClient.bind(this));

    return router;
  }

  async populateClientId (req, res, next, clientId) {
    const { oauth2: oauth2Service } = this.dtp.services;
    try {
      res.locals.serviceNode = await oauth2Service.getClientById(clientId);
      if (!res.locals.serviceNode) {
        throw new SiteError(404, 'Service node not found');
      }
      return next();
    } catch (error) {
      this.log.error('failed to populate OAuth2 client', { clientId, error });
      return next(error);
    }
  }

  async populateConnectRequestId (req, res, next, connectRequestId) {
    const { coreNode: coreNodeService } = this.dtp.services;
    try {
      res.locals.coreConnect = await coreNodeService.getCoreConnectRequest(connectRequestId);
      if (!res.locals.coreConnect) {
        throw new SiteError(404, 'Core Connect request not found');
      }
      return next();
    } catch (error) {
      this.log.error('failed to populate connectRequestId', { connectRequestId, error });
      return next(error);
    }
  }

  async postConnectRequestResponse (req, res/*, next*/) {
    this.log.info('processing Core Connect response', { coreConnect: res.locals.coreConnect, action: req.body.action });
    res.status(200).json({ success: true, coreConnect: res.locals.coreConnect });
  }

  async postClientUpdate (req, res, next) {
    const { oauth2: oauth2Service } = this.dtp.services;
    try {
      await oauth2Service.updateClient(res.locals.serviceNode, req.body);
      res.redirect('/admin/service-node');
    } catch (error) {
      this.log.error('failed to update OAuth2 client', { error });
      return next(error);
    }
  }

  async getServiceNodeConnectQueue (req, res, next) {
    const { coreNode: coreNodeService } = this.dtp.services;
    try {
      res.locals.pagination = this.getPaginationParameters(req, 20);
      res.locals.connectQueue = await coreNodeService.getServiceNodeQueue(res.locals.pagination);
      res.render('admin/service-node/connect-queue');
    } catch (error) {
      this.log.error('failed to render Core Connect queue', { error });
      return next(error);
    }
  }

  async getClientView (req, res) {
    res.render('admin/service-node/editor');
  }

  async getIndex (req, res, next) {
    const { oauth2: oauth2Service } = this.dtp.services;
    try {
      res.locals.pagination = this.getPaginationParameters(req, 20);
      res.locals.serviceNodes = await oauth2Service.getClients({ }, res.locals.pagination);
      res.render('admin/service-node/index');
    } catch (error) {
      this.log.error('failed to render Service Node home', { error });
      return next(error);
    }
  }

  async deleteClient (req, res) {
    const { oauth2: oauth2Service } = this.dtp.services;
    try {
      await oauth2Service.removeClient(res.locals.serviceNode);

      const displayList = this.createDisplayList('delete-newsletter');
      displayList.navigateTo('/admin/service-node');
      res.status(200).json({ success: true, displayList });
    } catch (error) {
      this.log.error('failed to delete client', { clientId: res.locals.serviceNode._id, error });
      return res.status(error.statusCode || 500).json({
        success: false,
        message: error.message,
      });
    }
  }
}

module.exports = {
  name: 'adminServiceNode',
  slug: 'admin-service-node',
  create: async (dtp) => { return new ServiceNodeController(dtp); },
};