import static org.junit.jupiter.api.Assertions.*;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;


import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Constructor;
import java.util.ArrayList;

class AnimalTest {

	@Test
	@DisplayName("Test for eat methods")
	void eatTest() {
		Wolf wolf1 = new Wolf(2, "Tim");
		Meat meat1 = new Meat("Venison");
		
		int no_eat = 5;

    	ByteArrayOutputStream baos = new ByteArrayOutputStream();
    	PrintStream ps = new PrintStream(baos);
    	PrintStream old = System.out;
    	System.setOut(ps);
    	wolf1.eat(meat1, 5);
    	System.out.flush();
    	System.setOut(old);
    	
    	int no_noise = baos.toString().split("\n").length;
    	
    	assertEquals(no_noise, no_eat, "Testing that a new line is printed with an eating message or noise");
    	
    	Method[] methods = wolf1.getClass().getSuperclass().getSuperclass().getDeclaredMethods();
    	
    	ArrayList<Method> eatMethods = new ArrayList<Method> ();
    	
    	for(int i = 0; i<methods.length; i++) {
    		String methodName = methods[i].getName();
    		if(methodName.equals("eat")) {
    			Parameter[] params = methods[i].getParameters();
        		ArrayList<String> eatParams = new ArrayList<String> ();
    			
    			for(int ii=0; ii<params.length; ii++) {
        			String p = params[ii].toString();
    				if(p.equals("Food arg0") || p.equals("java.lang.Integer arg1")) {
    					eatParams.add(p);
    				}
        		}
    			
    			if(eatParams.size()==2|| eatParams.size()==1) {
    				eatMethods.add(methods[i]);
    			}
    		}
    	}
    	
    	assertEquals(eatMethods.size(), 2, "Testing that there are two eat methods in the Animal class");
    	
	}
	
	@Test
	@DisplayName("Test Parrot age methods")
	void parrotTest() {
		Integer age = 5;
		Parrot polly = new Parrot(age);
		Constructor[] pars = polly.getClass().getConstructors();
		
		for(int i = 0; i<pars.length; i++) {
			String con = pars[i].toString();
			if(con.endsWith("Parrot(java.lang.Integer,java.lang.String)")) {
				assertTrue(true, "Testing that there is a Parrot contrustor with signature (Integer, String)");
			}else {
				assertTrue(false, "Testing that there is a Parrot contrustor with signature (Integer, String)");
			}
			if(con.endsWith("Parrot(java.lang.Integer)")) {
				assertTrue(true, "Testing that there is a Parrot contrustor with signature (Integer)");
			}else {
				assertTrue(false, "Testing that there is a Parrot contrustor with signature (Integer)");
			}
		}
		assertEquals(polly.getAge(), age, "Testing polly's age is correct");
		
	}

	@Test
	@DisplayName("Test Wolf age methods")
	void AnimalTest() {
		Wolf wolf1 = new Wolf();
		Integer age = 5;
		Wolf wolf2 = new Wolf(age, "Fuzzy");
		
		Constructor[] pars = wolf1.getClass().getConstructors();
		assertEquals(pars.length, 2);
		
		assertEquals(wolf1.getAge().intValue(), 0, "Testing that the new born wolf's age is 0");
		assertEquals(wolf2.getAge(), age, "Testing that the new born wolf's age is correct");
		
	}
}
