import { Guild, GuildTextableChannel, Member, TextChannel } from 'eris';
import { v4 as genUUID } from 'uuid';
import { Request } from 'express';
import { RichEmbed, Route, Server } from '../../../class';
import { StaffInterface } from '../../../models';

export default class Root extends Route {
  constructor(server: Server) {
    super(server);
    this.conf = {
      path: '/api',
    };

    this.server.client.once('ready', async () => {
      this.guild = this.server.client.guilds.get(this.server.client.config.guildID) || await this.server.client.getRESTGuild(this.server.client.config.guildID);
      this.directorRole = '662163685439045632';
      this.directorLogs = <TextChannel>this.guild.channels.get('807444198969835550');
      this.chairman = '278620217221971968';
    });
  }

  private guild: Guild;

  private directorRole: string;

  private directorLogs: GuildTextableChannel;

  private chairman: string;

  private async authenticate(req: Request) {
    if (!req.headers.authorization) return false;

    const users = await this.server.client.db.Score.find();
    const director = users.find((user) => user.pin.join('-') === req.headers.authorization);
    if (!director) return false;

    const member = this.guild.members.get(director.userID);
    if (!member) return false;
    if (!member.roles.includes(this.directorRole)) return false;

    const staffProfile = await this.server.client.db.Staff.findOne({ userID: member.id });

    return { member, director: staffProfile };
  }

  private genEmbed(
    id: string,
    type: 'eo' | 'motion' | 'proc' | 'res' | 'confirmMotion',
    director: {
      user: StaffInterface,
      member: Member
    },
    payload: {
      subject: string,
      body: string,
    },
  ) {
    let title: string;
    let color: number;

    switch (type) {
      case 'eo':
        title = 'Executive Order';
        color = 0xff00a7;
        this.server.client.util.transporter.sendMail({
          to: 'all-staff@lists.libraryofcode.org',
          from: 'Board Register System <internal@staff.libraryofcode.org>',
          subject: `EXECUTIVE ORDER ${id}`,
          text: `
          EXECUTIVE ORDER ${id}

          ISSUED BY:
            ${director.member.username}, ${director.user.pn.join(', ')}
          
          SUBJECT:
            ${payload.subject}
          
          BODY:
            ${payload.body}

          _____________________________________________________________________
          LIBRARY OF CODE SP-US | BOARD OF DIRECTORS
          BOARD REGISTER SYSTEM https://board.ins/
          `,
        });
        break;

      case 'motion':
        title = 'Motion';
        color = 0xffbb5f;
        break;

      case 'proc':
        title = 'Proclamation';
        color = 0x9b89ff;
        break;

      case 'res':
        title = 'Resolution';
        color = 0x27b17a;
        this.server.client.util.transporter.sendMail({
          to: 'all-staff@lists.libraryofcode.org',
          from: 'Board Register System <internal@staff.libraryofcode.org>',
          subject: `RESOLUTION ${id}`,
          text: `
          RESOLUTION ${id}

          SPONSOR:
            ${director.member.username}, ${director.user.pn.join(', ')}
          
          SUBJECT:
            ${payload.subject}
          
          BODY:
            ${payload.body}

          _____________________________________________________________________
          LIBRARY OF CODE SP-US | BOARD OF DIRECTORS
          BOARD REGISTER SYSTEM https://board.ins/
          `,
        });
        break;

      case 'confirmMotion':
        title = 'Motion Confirmed';
        color = 0x4a6cc5;
        break;

      default:
        throw new TypeError('You\'ve specified an invalid type for this action log. Valid types: "eo", "motion", "proc" and "res"');
    }

    const embed = new RichEmbed();
    embed.setTitle(title);
    embed.setAuthor(`${director.member.username}#${director.member.discriminator}, ${director.user.pn.join(', ')}`, director.member.avatarURL);
    embed.setDescription(`${id}\n\n_This action is available on the Board Register System Directory. You can make changes or edit it [here](https://board.ins/repository)._`);
    embed.addField('Subject', payload.subject);
    embed.addField('Body', payload.body);
    embed.setColor(color);
    embed.setFooter('Library of Code sp-us | Board Register System', 'https://static.libraryofcode.org/library_of_code.png');
    embed.setTimestamp();

    return embed;
  }

  public bind() {
    this.router.all('/', (_req, res, next) => {
      res.setHeader('Control-Allow-Access-Origin', '*');
      next();
    });

    this.router.get('/', async (req, res) => {
      const page = !Number.isNaN(Number(req.query.page)) ? Number(req.query.page) : 0;

      const counts = {
        eo: await this.server.client.db.ExecutiveOrder.countDocuments(),
        motion: await this.server.client.db.Motion.countDocuments(),
        proc: await this.server.client.db.Proclamation.countDocuments(),
        resolution: await this.server.client.db.Resolution.countDocuments(),
      };

      const eo = await this.server.client.db.ExecutiveOrder.find().skip(page * 4);
      const motion = await this.server.client.db.Motion.find().skip(page * 4);
      const proc = await this.server.client.db.Proclamation.find().skip(page * 4);
      const resolution = await this.server.client.db.Resolution.find().skip(page * 4);

      const returned: {
        id: string;
        author: string;
        subject: string;
        type: string;
        at: number;
      }[] = [];

      for (const item of eo) {
        const member = this.guild.members.get(item.issuer);
        const author = member ? `${member.username}#${member.discriminator}` : 'Deleted User#0000';

        returned.push({
          id: item.oID,
          author,
          subject: item.subject,
          type: 'Executive Order',
          at: item.at,
        });
      }

      for (const item of motion) {
        const member = this.guild.members.get(item.issuer);
        const author = member ? `${member.username}#${member.discriminator}` : 'Deleted User#0000';

        returned.push({
          id: item.oID,
          author,
          subject: item.subject,
          type: 'Motion',
          at: item.at,
        });
      }

      for (const item of proc) {
        const member = this.guild.members.get(item.issuer);
        const author = member ? `${member.username}#${member.discriminator}` : 'Deleted User#0000';

        returned.push({
          id: item.oID,
          author,
          subject: item.subject,
          type: 'Proclamation',
          at: item.at,
        });
      }

      for (const item of resolution) {
        const member = this.guild.members.get(item.issuer);
        const author = member ? `${member.username}#${member.discriminator}` : 'Deleted User#0000';

        returned.push({
          id: item.oID,
          author,
          subject: item.subject,
          type: 'Resolution',
          at: item.at,
        });
      }

      returned.sort((a, b) => a.at - b.at);

      const total = counts.eo + counts.motion + counts.proc + counts.resolution;

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        results: returned,
        total,
      });
    });

    this.router.get('/identify', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).send({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: `You have authenticated as a Director. Welcome ${authenticated.member.username}#${authenticated.member.discriminator}.`,
        user: {
          username: authenticated.member.username,
          discriminator: authenticated.member.discriminator,
          id: authenticated.member.id,
          avatarURL: authenticated.member.avatarURL || authenticated.member.defaultAvatarURL,
        },
      });
    });

    this.router.post('/eo', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).send({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 256 || req.body.body.length > 1024) {
        return res.status(400).json({
          code: this.constants.codes.CLIENT_ERROR,
          message: this.constants.messages.CLIENT_ERROR,
        });
      }

      const id = genUUID();
      const embed = this.genEmbed(
        id,
        'eo',
        {
          user: authenticated.director,
          member: authenticated.member,
        },
        {
          subject: req.body.subject,
          body: req.body.body,
        },
      );
      const msg = await this.directorLogs.createMessage({ embed });

      const eo = await this.server.client.db.ExecutiveOrder.create({
        issuer: authenticated.director.userID,
        subject: req.body.subject,
        body: req.body.body,
        at: Date.now(),
        oID: id,
        msg: msg.id,
      });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: `Created new Executive Order with ID ${eo.oID} by ${authenticated.member.username}#${authenticated.member.discriminator}`,
      });
    });

    this.router.post('/motion', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).send({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 256 || req.body.body.length > 1024) {
        return res.status(400).json({
          code: this.constants.codes.CLIENT_ERROR,
          message: this.constants.messages.CLIENT_ERROR,
        });
      }

      const id = genUUID();
      const embed = this.genEmbed(
        id,
        'motion',
        {
          user: authenticated.director,
          member: authenticated.member,
        },
        {
          subject: req.body.subject,
          body: req.body.body,
        },
      );
      const msg = await this.directorLogs.createMessage({ embed });

      const motion = await this.server.client.db.Motion.create({
        issuer: authenticated.director.userID,
        subject: req.body.subject,
        body: req.body.body,
        at: Date.now(),
        oID: id,
        processed: false,
        msg: msg.id,
      });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: `Created new Motion with ID ${motion.oID} by ${authenticated.member.username}#${authenticated.member.discriminator}`,
      });
    });

    this.router.post('/proc', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).send({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      if (typeof req.body.subject !== 'string' || typeof req.body.body !== 'string' || req.body.subject.length > 256 || req.body.body.length > 1024) {
        return res.status(400).json({
          code: this.constants.codes.CLIENT_ERROR,
          message: this.constants.messages.CLIENT_ERROR,
        });
      }

      const id = genUUID();
      const embed = this.genEmbed(
        id,
        'proc',
        {
          user: authenticated.director,
          member: authenticated.member,
        },
        {
          subject: req.body.subject,
          body: req.body.body,
        },
      );
      const msg = await this.directorLogs.createMessage({ embed });
      await msg.addReaction('modSuccess:578750988907970567');
      await msg.addReaction('modError:578750737920688128');
      await msg.addReaction('🙋');

      const proc = await this.server.client.db.Proclamation.create({
        issuer: authenticated.director.userID,
        subject: req.body.subject,
        body: req.body.body,
        at: Date.now(),
        oID: id,
        processed: false,
        msg: msg.id,
        results: {
          yea: 0,
          nay: 0,
          present: 0,
          absent: 0,
        },
        votedDirectors: [],
      });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: `Created new Proclamation with ID ${proc.oID} by ${authenticated.member.username}#${authenticated.member.discriminator}`,
      });
    });

    this.router.delete('/eo/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const eo = await this.server.client.db.ExecutiveOrder.findOne({ oID: req.params.id });

      if (!eo) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if (eo.issuer !== authenticated.member.id && authenticated.member.id !== this.chairman) {
        return res.status(403).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.codes.UNAUTHORIZED,
        });
      }

      await this.server.client.db.ExecutiveOrder.deleteOne({ _id: eo._id });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Executive Order deleted.',
      });
    });

    this.router.delete('/motion/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id });

      if (!motion) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if ((motion.issuer !== authenticated.member.id || motion.processed) && authenticated.member.id !== this.chairman) {
        return res.status(403).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.codes.UNAUTHORIZED,
        });
      }

      await this.server.client.db.Motion.deleteOne({ _id: motion._id });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Motion deleted.',
      });
    });

    this.router.delete('/proc/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const proc = await this.server.client.db.Proclamation.findOne({ oID: req.params.id });

      if (!proc) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if ((proc.issuer !== authenticated.member.id || proc.processed) && authenticated.member.id !== this.chairman) {
        return res.status(403).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.codes.UNAUTHORIZED,
        });
      }

      await this.server.client.db.Proclamation.deleteOne({ _id: proc._id });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Proclamation deleted.',
      });
    });

    this.router.get('/eo/:id', async (req, res) => {
      const eo = await this.server.client.db.ExecutiveOrder.findOne({ oID: req.params.id });

      if (!eo) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      const issuer = this.guild.members.get(eo.issuer);
      const director = await this.server.client.db.Staff.findOne({ userID: issuer.id });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        issuer: {
          username: issuer.username,
          discriminator: issuer.discriminator,
          avatarURL: issuer.avatarURL,
          id: issuer.id,
          pn: director.pn,
        },
        subject: eo.subject,
        body: eo.body,
        issuedAt: eo.at,
        id: eo.oID,
      });
    });

    this.router.get('/motion/:id', async (req, res) => {
      const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id });

      if (!motion) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      const issuer = this.guild.members.get(motion.issuer);
      const director = await this.server.client.db.Staff.findOne({ userID: issuer.id });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        issuer: {
          username: issuer.username,
          discriminator: issuer.discriminator,
          avatarURL: issuer.avatarURL,
          id: issuer.id,
          pn: director.pn,
        },
        subject: motion.subject,
        body: motion.body,
        issuedAt: motion.at,
        id: motion.oID,
        voteResults: motion.results || null,
        processed: motion.processed,
      });
    });

    this.router.get('/proc/:id', async (req, res) => {
      const proc = await this.server.client.db.Proclamation.findOne({ oID: req.params.id });

      if (!proc) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      const issuer = this.guild.members.get(proc.issuer);
      const director = await this.server.client.db.Staff.findOne({ userID: issuer.id });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        issuer: {
          username: issuer.username,
          discriminator: issuer.discriminator,
          avatarURL: issuer.avatarURL,
          id: issuer.id,
          pn: director.pn,
        },
        subject: proc.subject,
        body: proc.body,
        issuedAt: proc.at,
        id: proc.oID,
        voteResults: proc.results || null,
        processed: proc.processed,
      });
    });

    this.router.get('/resolution/:id', async (req, res) => {
      const resolution = await this.server.client.db.Resolution.findOne({ oID: req.params.id });

      if (!resolution) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      const issuer = this.guild.members.get(resolution.issuer);
      const director = await this.server.client.db.Staff.findOne({ userID: issuer.id });

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        issuer: {
          username: issuer.username,
          discriminator: issuer.discriminator,
          avatarURL: issuer.avatarURL,
          id: issuer.id,
          pn: director.pn,
        },
        subject: resolution.subject,
        body: resolution.body,
        issuedAt: resolution.at,
        id: resolution.oID,
        voteResults: resolution.results || null,
      });
    });

    this.router.patch('/eo/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const eo = await this.server.client.db.ExecutiveOrder.findOne({ oID: req.params.id });

      if (!eo) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if (eo.issuer !== authenticated.member.id && authenticated.member.id !== this.chairman) {
        return res.status(403).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.codes.UNAUTHORIZED,
        });
      }

      await eo.updateOne({
        subject: req.body.subject || eo.subject,
        body: req.body.body || eo.body,
      });

      if (eo.subject !== req.body.subject || eo.body !== req.body.body) {
        const message = await this.directorLogs.getMessage(eo.msg);
        const embed = this.genEmbed(
          eo.oID,
          'eo',
          {
            user: authenticated.director,
            member: authenticated.member,
          },
          {
            subject: req.body.subject,
            body: req.body.body,
          },
        );

        await message.edit({ embed });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Updated Executive Order.',
      });
    });

    this.router.patch('/motion/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id });

      if (!motion) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if ((motion.issuer !== authenticated.member.id || motion.processed) && authenticated.member.id !== this.chairman) {
        return res.status(403).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.codes.UNAUTHORIZED,
        });
      }

      await motion.updateOne({
        subject: req.body.subject || motion.subject,
        body: req.body.body || motion.body,
      });

      if (motion.subject !== req.body.subject || motion.body !== req.body.body) {
        const message = await this.directorLogs.getMessage(motion.msg);
        const embed = this.genEmbed(
          motion.oID,
          'motion',
          {
            user: authenticated.director,
            member: authenticated.member,
          },
          {
            subject: req.body.subject,
            body: req.body.body,
          },
        );

        await message.edit({ embed });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Updated Motion.',
      });
    });

    this.router.patch('/proc/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const proc = await this.server.client.db.Proclamation.findOne({ oID: req.params.id });

      if (!proc) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if ((proc.issuer !== authenticated.member.id || proc.processed) && authenticated.member.id !== this.chairman) {
        return res.status(403).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.codes.UNAUTHORIZED,
        });
      }

      await proc.updateOne({
        subject: req.body.subject || proc.subject,
        body: req.body.body || proc.body,
      });

      if (proc.subject !== req.body.subject || proc.body !== req.body.body) {
        const message = await this.directorLogs.getMessage(proc.msg);
        const embed = this.genEmbed(
          proc.oID,
          'proc',
          {
            user: authenticated.director,
            member: authenticated.member,
          },
          {
            subject: req.body.subject,
            body: req.body.body,
          },
        );

        await message.edit({ embed });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Updated Proclamation.',
      });
    });

    this.router.patch('/resolution/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const resolution = await this.server.client.db.Resolution.findOne({ oID: req.params.id });

      if (!resolution) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if (authenticated.member.id !== this.chairman) {
        return res.status(403).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.codes.UNAUTHORIZED,
        });
      }

      await resolution.updateOne({
        subject: req.body.subject || resolution.subject,
        body: req.body.body || resolution.body,
      });

      if (resolution.subject !== req.body.subject || resolution.body !== req.body.body) {
        const message = await this.directorLogs.getMessage(resolution.msg);
        const embed = this.genEmbed(
          resolution.oID,
          'res',
          {
            user: authenticated.director,
            member: authenticated.member,
          },
          {
            subject: req.body.subject,
            body: req.body.body,
          },
        );

        await message.edit({ embed });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Updated Resolution.',
      });
    });

    this.router.get('/eo', async (req, res) => {
      const page = !Number.isNaN(Number(req.query.page)) ? Number(req.query.page) : 0;
      const skipped = page || page * 10;

      const eo = await this.server.client.db.ExecutiveOrder.find().skip(skipped);
      const returned: {
        oID: string;
        author: string;
        issuedAt: number;
      }[] = [];

      for (const result of eo) {
        const director = this.guild.members.get(result.issuer);
        const author = director ? `${director.username}#${director.discriminator}` : 'Deleted User#0000';

        returned.push({
          oID: result.oID,
          author,
          issuedAt: result.at,
        });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        results: returned,
      });
    });

    this.router.get('/motion', async (req, res) => {
      const page = !Number.isNaN(Number(req.query.page)) ? Number(req.query.page) : 0;
      const skipped = page || page * 10;

      const motion = await this.server.client.db.Motion.find().skip(skipped);
      const returned: {
        oID: string;
        author: string;
        issuedAt: number;
      }[] = [];

      for (const result of motion) {
        const director = this.guild.members.get(result.issuer);
        const author = director ? `${director.username}#${director.discriminator}` : 'Deleted User#0000';

        returned.push({
          oID: result.oID,
          author,
          issuedAt: result.at,
        });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        results: returned,
      });
    });

    this.router.get('/proc', async (req, res) => {
      const page = !Number.isNaN(Number(req.query.page)) ? Number(req.query.page) : 0;
      const skipped = page || page * 10;

      const proc = await this.server.client.db.Proclamation.find().skip(skipped);
      const returned: {
        oID: string;
        author: string;
        issuedAt: number;
      }[] = [];

      for (const result of proc) {
        const director = this.guild.members.get(result.issuer);
        const author = director ? `${director.username}#${director.discriminator}` : 'Deleted User#0000';

        returned.push({
          oID: result.oID,
          author,
          issuedAt: result.at,
        });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        results: returned,
      });
    });

    this.router.get('/resolution', async (req, res) => {
      const page = !Number.isNaN(Number(req.query.page)) ? Number(req.query.page) : 0;
      const skipped = page || page * 10;

      const resolution = await this.server.client.db.Resolution.find().skip(skipped);
      const returned: {
        oID: string;
        author: string;
        issuedAt: number;
      }[] = [];

      for (const result of resolution) {
        const director = this.guild.members.get(result.issuer);
        const author = director ? `${director.username}#${director.discriminator}` : 'Deleted User#0000';

        returned.push({
          oID: result.oID,
          author,
          issuedAt: result.at,
        });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        results: returned,
      });
    });

    this.router.put('/motion/confirm/:id', async (req, res) => {
      const authenticated = await this.authenticate(req);
      if (!authenticated) {
        return res.status(401).json({
          code: this.constants.codes.UNAUTHORIZED,
          message: this.constants.messages.UNAUTHORIZED,
        });
      }

      const motion = await this.server.client.db.Motion.findOne({ oID: req.params.id });

      if (!motion) {
        return res.status(404).json({
          code: this.constants.codes.NOT_FOUND,
          message: this.constants.messages.NOT_FOUND,
        });
      }

      if (Number.isNaN(Number(req.body.yea)) || Number.isNaN(Number(req.body.nay)) || Number.isNaN(Number(req.body.present))) {
        return res.status(400).json({
          code: this.constants.codes.CLIENT_ERROR,
          message: this.constants.messages.CLIENT_ERROR,
        });
      }

      const yea = Number(req.body.yea);
      const nay = Number(req.body.nay);
      const present = Number(req.body.present);
      const total = this.guild.members.filter((member) => member.roles.includes(this.directorRole));
      const absent = total.length - (yea + nay + present);

      await motion.updateOne({
        processed: true,
        results: {
          yea,
          nay,
          present,
          absent,
        },
      });

      const confirmationEmbed = this.genEmbed(
        motion.oID,
        'confirmMotion',
        {
          user: authenticated.director,
          member: authenticated.member,
        },
        {
          subject: motion.subject,
          body: motion.body,
        },
      );
      confirmationEmbed.addField('Results', `**Total:** ${total.length}\n**Yea:** ${yea}\n**Nay:** ${nay}\n**Present:** ${present}\n**Absent:** ${absent}`);
      await this.directorLogs.createMessage({ embed: confirmationEmbed });

      const totalDirectors = yea + nay + present + absent;
      if (yea / totalDirectors >= 0.6) {
        const resolutionEmbed = this.genEmbed(
          motion.oID,
          'res',
          {
            user: authenticated.director,
            member: authenticated.member,
          },
          {
            subject: motion.subject,
            body: motion.body,
          },
        );
        const resolutionMessage = await this.directorLogs.createMessage({ embed: resolutionEmbed });
        const resolutionID = genUUID();

        await this.server.client.db.Resolution.create({
          issuer: motion.issuer,
          subject: motion.subject,
          body: motion.body,
          at: Date.now(),
          oID: resolutionID,
          results: {
            yea,
            nay,
            present,
            absent,
          },
          msg: resolutionMessage.id,
        });
      }

      res.status(200).json({
        code: this.constants.codes.SUCCESS,
        message: 'Confirmed the results of the Motion.',
      });
    });
  }
}
