package fr.umlv.examir2;

import static java.util.stream.Collectors.toSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.IntStream;

import org.junit.Test;

@SuppressWarnings("static-method")
public class CompanyTest {
  @Test
  public void testCreatePerson() {
    Company company = new Company();
    Person bob = company.createPerson("bob");
    Person danna = company.createPerson("danna");
    assertNotEquals(bob, danna);
  }
  @Test(expected = IllegalStateException.class)
  public void testCreatePersonTwice() {
    Company company = new Company();
    company.createPerson("patty");
    company.createPerson("patty");
  }
  @Test(expected = NullPointerException.class)
  public void testCreatePersonNull() {
    Company company = new Company();
    company.createPerson(null);
  }

  @Test
  public void testGetPersonFromName() {
    Company company = new Company();
    Person ajah = company.createPerson("ajah");
    company.createPerson("elohim");
    assertEquals(ajah, company.getPersonFromName("ajah").orElse(null));
  }
  @Test
  public void testGetPersonFromName2() {
    Company company = new Company();
    company.createPerson("iris");
    company.getPersonFromName("dylan").ifPresent(__ -> fail());
  }
  @Test(expected = NullPointerException.class)
  public void testGetPersonFromNameNull() {
    Company company = new Company();
    company.getPersonFromName(null);
  }

  @Test
  public void testGetAllPersons() {
    Company company = new Company();
    Set<Person> list = IntStream.range(0, 100).mapToObj(i -> company.createPerson("id" + i)).collect(toSet());
    Collection<Person> all = company.getAllPersons();
    assertEquals(list.size(), all.size());
    all.forEach(p -> assertTrue(list.contains(p)));
  }
  
  @Test
  public void testGetAllPersonByPrimaryAddress() {
    Company company = new Company();
    company.createPerson("sia");
    Person david = company.createPerson("david");
    david.addAddress(new Address("4 cine plazza"));
    Map<Address, List<Person>> personByPrimaryAddress = company.getAllPersonByPrimaryAddress();
    assertEquals(1, personByPrimaryAddress.size());
    assertTrue(personByPrimaryAddress.containsKey(new Address("4 cine plazza")));
    assertEquals(List.of(david), personByPrimaryAddress.get(new Address("4 cine plazza")));
  }
  
  @Test
  public void testGetAllPersonByPrimaryAddress2() {
    Company company = new Company();
    Person spiderman = company.createPerson("spiderman");
    Person superman = company.createPerson("superman");
    spiderman.addAddress(new Address("7 spidey center"));
    superman.addAddress(new Address("7 spidey center"));
    Map<Address, List<Person>> personByPrimaryAddress = company.getAllPersonByPrimaryAddress();
    assertEquals(1, personByPrimaryAddress.size());
    assertTrue(personByPrimaryAddress.containsKey(new Address("7 spidey center")));
    assertTrue(personByPrimaryAddress.get(new Address("7 spidey center")).contains(spiderman));
    assertTrue(personByPrimaryAddress.get(new Address("7 spidey center")).contains(superman));
  }
  
  @Test
  public void testGetAllPersonByAddress() {
    Company company = new Company();
    company.createPerson("john");
    Person ringo = company.createPerson("ringo");
    ringo.addAddress(new Address("4 sky street"));
    Person lucy = company.createPerson("lucy");
    lucy.addAddress(new Address("4 sky street"));
    lucy.addAddress(new Address("4 diamond street"));
    Map<Address, List<Person>> personByAddress = company.getAllPersonByAddress();
    assertEquals(2, personByAddress.size());
    assertTrue(personByAddress.containsKey(new Address("4 sky street")));
    assertTrue(personByAddress.containsKey(new Address("4 diamond street")));
    assertEquals(Set.of(ringo, lucy), personByAddress.get(new Address("4 sky street")).stream().collect(toSet()));
    assertEquals(List.of(lucy), personByAddress.get(new Address("4 diamond street")));
  }
  
  @Test
  public void testGetAllPersonByAddress2() {
    Company company = new Company();
    IntStream.range(0, 10).forEach(i -> {
      Person person = company.createPerson("" + i);
      IntStream.range(0, i).forEach(j -> person.addAddress(new Address("" + j)));
    });
    Map<Address, List<Person>> personByAddress = company.getAllPersonByAddress();
    assertEquals(9, personByAddress.size());
    personByAddress.forEach((address, persons) -> {
      int addressId = Integer.parseInt(address.getStreet());
      persons.forEach(person -> {
        int personId = Integer.parseInt(person.getName());
        assertTrue(personId > addressId);
      }); 
    });
  }

  @Test
  public void testGetAllPersonAt() {
    Company company = new Company();
    company.createPerson("adolf");
    Person josef = company.createPerson("josef");
    josef.addAddress(new Address("7 doom street"));
    Person nikita = company.createPerson("nikita");
    nikita.addAddress(new Address("13 bomb avenue"));
    nikita.addAddress(new Address("7 doom street"));
    
    List<Person> peopleAtValueStreet = company.getAllPersonAt(new Address("42 value street"));
    assertEquals(List.of(), peopleAtValueStreet);
    
    List<Person> peopleAtBombAvenue = company.getAllPersonAt(new Address("13 bomb avenue"));
    assertEquals(List.of(nikita), peopleAtBombAvenue);
    
    List<Person> peopleAtDoomStreet = company.getAllPersonAt(new Address("7 doom street"));
    assertEquals(Set.of(josef, nikita), peopleAtDoomStreet.stream().collect(toSet()));
  }
}
