type MastoClient = {
  id: string,
  name: string,
  website?: string,
  redirect_uri: string,
  client_id: string,
  client_secret: string, 
  vapid_key: string,
}

type MastoToken = {
  access_token: string,
  token_type: string,
  scope: string,
  created_at: number
}

export class MastoAuth {
  instance: string;

  constructor(instance:string) {
    this.instance = instance;
  }

  async newApplication() {
    let formData = new FormData();
    formData.append('client_name', 'abtmtr.link Jams');
    formData.append('redirect_uris', 'https://abtmtr.link/jams/oauth/code');
    // formData.append('redirect_uris', 'http://localhost:3000/jams/oauth/code');
    formData.append('scopes', 'read');
    formData.append('website', 'https://abtmtr.link/jams');

    let appRequest;
    try {
      appRequest = await fetch(`https://${this.instance}/api/v1/apps`, {
          body: formData,
          method: "post"
      });
    } catch (err) {
      console.log(err);
      return null;
    }

    if (appRequest.ok) {
      const reqEntities:MastoClient = await appRequest.json();
      return reqEntities;
    } else return null;
  }

  // async getApplicationUserCode(client: MastoClient) {
  //   let formData = new FormData();
  //   formData.append('response_type', 'code');
  //   formData.append('client_id', client.client_id);
  //   formData.append('redirect_uri', client.redirect_uri);
  //   formData.append('scope', 'read');
  //   formData.append('force_login', 'true');

  //   const appRequest = await fetch(`https://${this.instance}/oauth/authorize`, {
  //     body: formData
  //   });

  //   if (appRequest.ok) {
  //     const reqEntities:MastoToken = await appRequest.json();
  //     return reqEntities;
  //   } else return null;
  // }

  async getApplicationToken(client: {
    client_id: string, client_secret: string,
    redirect_uri: string
  }, code:string) {
    let formData = new FormData();
    formData.append('client_id', client.client_id);
    formData.append('client_secret', client.client_secret);
    formData.append('redirect_uri', client.redirect_uri);
    if (this.instance != "github.com")
      formData.append('grant_type', 'authorization_code');
    formData.append('code', code);
    if (this.instance == "discord.com")
      formData.append('scope', 'identify');
    else if (this.instance != "github.com")
      formData.append('scope', 'read');

    let appRequest;
    try {
      if (this.instance == "discord.com") {
        appRequest = await fetch(`https://${this.instance}/api/v10/oauth2/token`, {
          body: formData,
          method: "post",
          headers: {
            "Accept": "application/json"
          }
        });
      } else if (this.instance == "github.com") {
        appRequest = await fetch(`https://${this.instance}/login/oauth/access_token`, {
          body: formData,
          method: "post",
          headers: {
            "Accept": "application/json"
          }
        });
      } else {
        appRequest = await fetch(`https://${this.instance}/oauth/token`, {
          body: formData,
          method: "post"
        });
      }
    } catch (err) {
      console.log(err);
      return null;
    }

    if (appRequest.ok) {
      const reqEntities:{
        access_token: string,
        token_type: string,
        scope: string,
        created_at?: number
      } = await appRequest.json();
      return reqEntities;
    } else return null;
  }

  async verifyUser(auth: string) {
    let appRequest;
    try { 
      if (this.instance == "discord.com") {
        appRequest = await fetch(`https://${this.instance}/api/v10/oauth2/@me`, {
          headers: {
            "Authorization": auth
          }
        });
      } else if (this.instance == "github.com") {
        appRequest = await fetch(`https://api.${this.instance}/user`, {
          headers: {
            "Authorization": auth
          }
        });
      } else {
        appRequest = await fetch(`https://${this.instance}/api/v1/accounts/verify_credentials`, {
          headers: {
            "Authorization": auth
          }
        });
      }
    } catch (err) {
      console.log(err);
      return null;
    }

    if (appRequest.ok) {
      const reqEntities = await appRequest.json();
      return reqEntities;
    } else return null;
  }
}