package org.telegram.abilitybots.api.bot;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.telegram.abilitybots.api.objects.Ability;
import org.telegram.abilitybots.api.util.AbilityExtension;

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
import static org.telegram.abilitybots.api.objects.Locality.ALL;
import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC;

class ExtensionTest {
  private ExtensionUsingBot bot;

  @BeforeEach
  void setUp() {
    bot = new ExtensionUsingBot();
    bot.onRegister();
  }

  @AfterEach
  void tearDown() throws IOException {
    bot.db.clear();
    bot.db.close();
  }

  @Test
  void methodReturningAbilities() {
    assertTrue(hasAbilityNamed("direct"), "Failed to find Ability in directly declared in root extension/bot");
    assertTrue(hasAbilityNamed("returningSuperClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension class");
    assertTrue(hasAbilityNamed("returningSubClass0abc"), "Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension subclass");
    assertTrue(hasAbilityNamed("addedInConstructor0abc"), "Failed to find Ability in directly declared in extension added in the constructor");
  }

  private boolean hasAbilityNamed(String name) {
    return bot.abilities().values().stream().map(Ability::name).anyMatch(name::equals);
  }

  public static class ExtensionUsingBot extends AbilityBot {
    ExtensionUsingBot() {
      super("", "", offlineInstance("testing"));
      addExtension(new AbilityBotExtension("addedInConstructor", this));
    }

    @Override
    public long creatorId() {
      return 0;
    }

    public AbilityBotExtension methodReturningExtensionSubClass() {
      return new AbilityBotExtension("returningSubClass", this);
    }

    public AbilityExtension methodReturningExtensionSuperClass() {
      return new AbilityBotExtension("returningSuperClass", this);
    }

    public Ability methodReturningAbility() {
      return Ability.builder()
              .name("direct")
              .info("Test ability")
              .locality(ALL)
              .privacy(PUBLIC)
              .action(messageContext -> {
              })
              .build();
    }
  }

  public static class AbilityBotExtension implements AbilityExtension {
    private String name;
    private AbilityBot extensionUser;

    AbilityBotExtension(String name, AbilityBot extensionUser) {
      this.name = name;
      this.extensionUser = extensionUser;
    }

    public Ability abc() {
      return Ability.builder()
              .name(name + "0abc")
              .info("Test ability")
              .locality(ALL)
              .privacy(PUBLIC)
              .action(ctx -> {
                extensionUser.silent().send("This is a test message.", ctx.chatId());
              })
              .build();
    }
  }
}
@@ -1677,29 +1677,149 @@
     
-ExtensionUsingBot() %7B
+/**%0A     * Constructor for ExtensionUsingBot%0A     */%0A    ExtensionUsingBot() %7B%0A      // https://github.com/rubenlagus/TelegramBots/issues/834
 %0A   
@@ -2003,32 +2003,136 @@
 eturn 0;%0A    %7D%0A%0A
+    /**%0A     * Method for returning AbiltyExtension%0A     * @return AbilityBotExtension instance%0A     */%0A
     public Abili
@@ -2175,32 +2175,95 @@
 ionSubClass() %7B%0A
+      // https://github.com/rubenlagus/TelegramBots/issues/834%0A
       return new
@@ -2310,32 +2310,136 @@
 , this);%0A    %7D%0A%0A
+    /**%0A     * Method for returning AbilityExtension%0A     * @return AbiltyBotExtension instance%0A     */%0A
     public Abili
@@ -2485,24 +2485,87 @@
 erClass() %7B%0A
+      // https://github.com/rubenlagus/TelegramBots/issues/834%0A
       return
@@ -3059,16 +3059,260 @@
 nUser;%0A%0A
+    /**%0A     * https://github.com/rubenlagus/TelegramBots/issues/721%0A     * Constructor for AbilityBotExtension%0A     * @param name Name of the ability extension%0A     * @param extensionUser The AbilityBot that uses this AbilityExtension%0A     */%0A
     Abil
@@ -3388,24 +3388,87 @@
 ame = name;%0A
+      // https://github.com/rubenlagus/TelegramBots/issues/834%0A
       this.e
@@ -3685,32 +3685,32 @@
 privacy(PUBLIC)%0A
-
               .a
@@ -3720,24 +3720,97 @@
 on(ctx -%3E %7B%0A
+                // https://github.com/rubenlagus/TelegramBots/issues/834%0A
             

Add javadoc and comments