package com.github.phantomthief.failover.impl;

import static com.google.common.base.Predicates.alwaysFalse;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import org.junit.jupiter.api.Test;

import com.github.phantomthief.failover.Failover;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

/**
 * @author w.vela
 */
class WeightFailoverTest {

    @Test
    void testCommon() {
        List<String> original = Arrays.asList("1", "2", "3");
        Failover<String> failover = WeightFailover.newBuilder() //
                .checker(this::check) //
                .build(original);
        Multiset<String> result = HashMultiset.create();
        Multiset<Integer> getCount = HashMultiset.create();
        for (int i = 0; i < 500; i++) {
            List<String> available = failover.getAvailable(2);
            assertTrue(available.size() <= 2);
            getCount.add(available.size());
            available.forEach(obj -> {
                assertNotNull(obj);
                if (doSomething(obj, failover)) {
                    result.add(obj);
                }
            });
            sleepUninterruptibly(10, MILLISECONDS);
        }
        System.out.println(getCount);
        System.out.println(result);
    }

    @Test
    void testMinWeight() {
        List<String> original = Arrays.asList("1", "2", "3");
        Failover<String> failover = WeightFailover.newBuilder() //
                .checker(this::check) //
                .minWeight(1) //
                .onMinWeight(i -> System.out.println("onMin:" + i)) //
                .build(original);
        Multiset<String> result = HashMultiset.create();
        Multiset<Integer> getCount = HashMultiset.create();
        for (int i = 0; i < 500; i++) {
            List<String> available = failover.getAvailable(2);
            assertTrue(available.size() == 2);
            getCount.add(available.size());
            available.forEach(obj -> {
                assertNotNull(obj);
                if (doSomething(obj, failover)) {
                    result.add(obj);
                }
            });
            sleepUninterruptibly(10, MILLISECONDS);
        }
        System.out.println(getCount);
        System.out.println(result);
    }

    @Test
    void testDown() {
        List<String> original = Arrays.asList("1", "2", "3");
        Failover<String> failover = WeightFailover.<String> newGenericBuilder() //
                .checker(alwaysFalse()) //
                .onMinWeight(i -> System.out.println("onMin:" + i)) //
                .build(original);
        Multiset<String> result = HashMultiset.create();
        Multiset<Integer> getCount = HashMultiset.create();
        failover.down("1");
        for (int i = 0; i < 500; i++) {
            String available = failover.getOneAvailable();
            assertNotEquals(available, "1");
            sleepUninterruptibly(10, MILLISECONDS);
        }
        System.out.println(getCount);
        System.out.println(result);
    }

    private boolean check(String test) {
        System.out.println("test:" + test);
        return true;
    }

    private boolean doSomething(String obj, Failover<String> failover) {
        boolean result = ThreadLocalRandom.current().nextInt(10) > Integer.parseInt(obj);
        if (result) {
            failover.success(obj);
        } else {
            failover.fail(obj);
        }
        return result;
    }
}

@@ -102,16 +102,76 @@
 sFalse;%0A
+import static com.google.common.base.Predicates.alwaysTrue;%0A
 import s
@@ -535,20 +535,68 @@
 va.util.
-List
+HashMap;%0Aimport java.util.List;%0Aimport java.util.Map
 ;%0Aimport
@@ -3500,32 +3500,722 @@
 result);%0A    %7D%0A%0A
+    @Test%0A    void testLarge() %7B%0A        Map%3CString, Integer%3E map = new HashMap%3C%3E();%0A        for (int i = 0; i %3C 108; i++) %7B%0A            map.put(%22i%22 + i, 32518);%0A        %7D%0A        for (int i = 0; i %3C 331; i++) %7B%0A            map.put(%22j%22 + i, 2652);%0A        %7D%0A        WeightFailover%3CString%3E failover = WeightFailover.%3CString%3E newGenericBuilder() //%0A                .checker(alwaysTrue()) //%0A                .build(map);%0A        Multiset%3CString%3E counter = HashMultiset.create();%0A        for (int i = 0; i %3C 100000; i++) %7B%0A            String oneAvailable = failover.getOneAvailable();%0A            counter.add(oneAvailable.substring(0, 1));%0A        %7D%0A        System.out.println(counter);%0A    %7D%0A%0A
     private bool

add test case for weight failover.