/**
 * Copyright 2020 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 */

package com.linkedin.kmf.consumer;

import com.linkedin.kmf.common.ConsumerGroupCoordinatorUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import org.apache.kafka.clients.admin.AdminClient;
import org.apache.kafka.clients.admin.DescribeTopicsResult;
import org.apache.kafka.clients.admin.TopicDescription;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.common.internals.KafkaFutureImpl;
import org.apache.kafka.common.internals.Topic;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;


@Test
public class NewConsumerTest {
  private static final int NUM_OFFSETS_TOPIC_PARTITIONS = 5;
  private static final String TARGET_CONSUMER_GROUP_ID = "target-group-id";

  @BeforeMethod
  public void beforeMethod() {
    System.out.println("Running beforeMethod of " + this.getClass());
  }

  @AfterMethod
  public void afterMethod() {
    System.out.println("Finished running testConsumerGroupCoordinatorHashing() of " + this.getClass());
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testConsumerGroupCoordinatorHashing() throws ExecutionException, InterruptedException {
    Properties consumerProperties = new Properties();

    AdminClient adminClient = Mockito.mock(AdminClient.class);

    /*
     * Mock the behavior of AdminClient only.
     */
    Mockito.when(adminClient.describeTopics(Collections.singleton(Topic.GROUP_METADATA_TOPIC_NAME)))
        .thenReturn(Mockito.mock(DescribeTopicsResult.class));
    Mockito.when(adminClient.describeTopics(Collections.singleton(Topic.GROUP_METADATA_TOPIC_NAME)).values())
        .thenReturn(Mockito.mock(Map.class));
    Mockito.when(adminClient.describeTopics(Collections.singleton(Topic.GROUP_METADATA_TOPIC_NAME))
        .values()
        .get(Topic.GROUP_METADATA_TOPIC_NAME)).thenReturn(Mockito.mock(KafkaFutureImpl.class));

    Mockito.when(adminClient.describeTopics(Collections.singleton(Topic.GROUP_METADATA_TOPIC_NAME))
        .values()
        .get(Topic.GROUP_METADATA_TOPIC_NAME)
        .get()).thenReturn(Mockito.mock(TopicDescription.class));

    Mockito.when(adminClient.describeTopics(Collections.singleton(Topic.GROUP_METADATA_TOPIC_NAME))
        .values()
        .get(Topic.GROUP_METADATA_TOPIC_NAME)
        .get()
        .partitions()).thenReturn(Mockito.mock(List.class));

    Mockito.when(adminClient.describeTopics(Collections.singleton(Topic.GROUP_METADATA_TOPIC_NAME))
        .values()
        .get(Topic.GROUP_METADATA_TOPIC_NAME)
        .get()
        .partitions()
        .size()).thenReturn(NUM_OFFSETS_TOPIC_PARTITIONS);

    consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG,
        NewConsumer.configureGroupId(TARGET_CONSUMER_GROUP_ID, adminClient));
    System.out.println("Consumer properties after configuration: " + consumerProperties);
    Assert.assertNotNull(consumerProperties.get(ConsumerConfig.GROUP_ID_CONFIG));

    // Testing I: run partitionsFor() on the result to make sure they are the same
    int hashedResult =
        ConsumerGroupCoordinatorUtils.partitionFor(consumerProperties.get(ConsumerConfig.GROUP_ID_CONFIG).toString(),
            NUM_OFFSETS_TOPIC_PARTITIONS);
    int hashedResult2 =
        ConsumerGroupCoordinatorUtils.partitionFor(TARGET_CONSUMER_GROUP_ID, NUM_OFFSETS_TOPIC_PARTITIONS);

    Assert.assertEquals(hashedResult, hashedResult2);
    System.out.println("Modulo result as an absolute value: " + hashedResult);
    System.out.println("Modulo result as an absolute value: " + hashedResult2);

    // Testing II: Also test that the groupIds are different.
    Assert.assertNotEquals(TARGET_CONSUMER_GROUP_ID, consumerProperties.get(ConsumerConfig.GROUP_ID_CONFIG));

  }
}