import axios, { AxiosResponse } from 'axios';
import { Client, CmdContext, Command, RichEmbed } from '../class';

import X509_Upload from './x509_upload';
import X509_Remove from './x509_remove';

export interface X509Certificate {
  status: boolean,
  message?: string,
  subject: {
    commonName: string,
    organization: string[],
    organizationalUnit: string[],
    locality: string[],
    country: string[],
  },
  issuer: {
    commonName: string,
    organization: string[],
    organizationalUnit: string[],
    locality: string[],
    country: string[],
  },
  root: {
    commonName: string,
    organization: string[],
    organizationalUnit: string[],
    locality: string[],
    country: string[],
  },
  notBefore: Date,
  notAfter: Date,
  validationType: 'DV' | 'OV' | 'EV',
  signatureAlgorithm: string,
  publicKeyAlgorithm: string,
  serialNumber: string,
  keyUsage: number[],
  keyUsageAsText: ['CRL Signing'?, 'Certificate Signing'?, 'Content Commitment'?, 'Data Encipherment'?, 'Decipher Only'?, 'Digital Signature'?, 'Encipher Only'?, 'Key Agreement'?, 'Key Encipherment'?],
  extendedKeyUsage: number[],
  extendedKeyUsageAsText: ['All/Any Usages'?, 'TLS Web Server Authentication'?, 'TLS Web Client Authentication'?, 'Code Signing'?, 'E-mail Protection (S/MIME)'?],
  san: string[],
  fingerprint: string,
  emailAddresses: string[],
  bitLength: number,
}

export default class X509 extends Command {
  constructor(client: Client) {
    super(client);
    this.name = 'x509';
    this.description = 'Uploads to or removes from your account an X.509 certificate.';
    this.usage = `${this.client.config.prefix}${this.name}`;
    this.permissions = 0;
    this.guildOnly = true;
    this.enabled = true;
    this.subcmds = [X509_Upload, X509_Remove];
  }

  public async run(ctx: CmdContext) {
    const profile = await this.client.db.mongo.Member.findOne({ userID: ctx.args[0] || ctx.message.author.id });
    if (!profile) return this.error(ctx.message.channel, 'Unable to find specified member\'s account.');
    const embed = new RichEmbed()
      .setAuthor(`${ctx.message.author.username}#${ctx.message.author.discriminator}`, ctx.message.author.dynamicAvatarURL())
      .setTitle('X.509 Connections')
      .setColor('#ffc63c')
      .setDescription(`There are no X.509 certificates connected to your account. Use \`${this.client.config.prefix}x509 upload\` to add one.`)
      .setTimestamp();
    if (profile?.x509) {
      embed.setColor('#2ecc71');
      const x509: AxiosResponse<X509Certificate> = await axios.post('https://certapi.libraryofcode.org/parse', profile.x509);
      embed.setDescription(`You currently have X.509 certificate **\`${x509.data.serialNumber}\`** linked to your account.`);
      embed.addField('Common Name', x509.data.subject.commonName, true);
      embed.addField('Issuer', x509.data.issuer.commonName, true);
      embed.addBlankField();
      embed.addField('Public Key Algorithm', x509.data.publicKeyAlgorithm, true);
      embed.addField('Not Before', new Date(x509.data.notBefore).toUTCString(), true);
      embed.addField('Not After', new Date(x509.data.notAfter).toUTCString(), true);
      if (x509.data.keyUsageAsText.length) embed.addField('Key Usages', x509.data.keyUsageAsText.join(', '), true);
      if (x509.data.extendedKeyUsageAsText.length) embed.addField('Extended Key Usages', x509.data.extendedKeyUsageAsText.join(', '), true);
    } else this.client.commands.get('help').run(new CmdContext(ctx.message, ['x509', 'upload']));
    ctx.message.channel.createMessage({ embed });
  }
}
