package seedu.address.logic.commands;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
import static seedu.address.testutil.TypicalPersons.CARL;
import static seedu.address.testutil.TypicalPersons.ELLE;
import static seedu.address.testutil.TypicalPersons.FIONA;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.Test;

import seedu.address.logic.CommandHistory;
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.NameContainsKeywordsPredicate;
import seedu.address.model.person.Person;

/**
 * Contains integration tests (interaction with the Model) for {@code FindCommand}.
 */
public class FindCommandTest {
    private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());

    @Test
    public void equals() {
        NameContainsKeywordsPredicate firstPredicate =
                new NameContainsKeywordsPredicate(Collections.singletonList("first"));
        NameContainsKeywordsPredicate secondPredicate =
                new NameContainsKeywordsPredicate(Collections.singletonList("second"));

        FindCommand findFirstCommand = new FindCommand(firstPredicate);
        FindCommand findSecondCommand = new FindCommand(secondPredicate);

        // same object -> returns true
        assertTrue(findFirstCommand.equals(findFirstCommand));

        // same values -> returns true
        FindCommand findFirstCommandCopy = new FindCommand(firstPredicate);
        assertTrue(findFirstCommand.equals(findFirstCommandCopy));

        // different types -> returns false
        assertFalse(findFirstCommand.equals(1));

        // null -> returns false
        assertFalse(findFirstCommand.equals(null));

        // different person -> returns false
        assertFalse(findFirstCommand.equals(findSecondCommand));
    }

    @Test
    public void execute_zeroKeywords_noPersonFound() {
        String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
        FindCommand command = prepareCommand(" ");
        assertCommandSuccess(command, expectedMessage, Collections.emptyList());
    }

    @Test
    public void execute_multipleKeywords_multiplePersonsFound() {
        String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
        FindCommand command = prepareCommand("Kurz Elle Kunz");
        assertCommandSuccess(command, expectedMessage, Arrays.asList(CARL, ELLE, FIONA));
    }

    /**
     * Parses {@code userInput} into a {@code FindCommand}.
     */
    private FindCommand prepareCommand(String userInput) {
        FindCommand command =
                new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+"))));
        command.setData(model, new CommandHistory());
        return command;
    }

    /**
     * Asserts that {@code command} is successfully executed, and<br>
     *     - the command feedback is equal to {@code expectedMessage}<br>
     *     - the {@code FilteredList<Person>} is equal to {@code expectedList}<br>
     *     - the {@code AddressBook} in model remains the same after executing the {@code command}
     */
    private void assertCommandSuccess(FindCommand command, String expectedMessage, List<Person> expectedList) {
        AddressBook expectedAddressBook = new AddressBook(model.getAddressBook());
        CommandResult commandResult = command.execute();

        assertEquals(expectedMessage, commandResult.feedbackToUser);
        assertEquals(expectedList, model.getFilteredPersonList());
        assertEquals(expectedAddressBook, model.getAddressBook());
    }
}

@@ -247,16 +247,97 @@
 ERVIEW;%0A
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;%0A
 import s
@@ -637,31 +637,8 @@
 ons;
-%0Aimport java.util.List;
 %0A%0Aim
@@ -706,48 +706,8 @@
 ry;%0A
-import seedu.address.model.AddressBook;%0A
 impo
@@ -883,50 +883,8 @@
 ate;
-%0Aimport seedu.address.model.person.Person;
 %0A%0A/*
@@ -1089,16 +1089,110 @@
 refs());
+%0A    private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
 %0A%0A    @T
@@ -2400,48 +2400,186 @@
     
-FindCommand command = prepareCommand(%22 %22
+NameContainsKeywordsPredicate predicate = preparePredicate(%22 %22);%0A        FindCommand command = prepareCommand(predicate);%0A        expectedModel.updateFilteredPersonList(predicate
 );%0A 
@@ -2606,32 +2606,39 @@
 Success(command,
+ model,
  expectedMessage
@@ -2643,25 +2643,93 @@
 ge, 
-Collections.empty
+expectedModel);%0A        assertEquals(Collections.emptyList(), model.getFilteredPerson
 List
@@ -2912,61 +2912,199 @@
     
-FindCommand command = prepareCommand(%22Kurz Elle Kunz%22
+NameContainsKeywordsPredicate predicate = preparePredicate(%22Kurz Elle Kunz%22);%0A        FindCommand command = prepareCommand(predicate);%0A        expectedModel.updateFilteredPersonList(predicate
 );%0A 
@@ -3139,16 +3139,23 @@
 command,
+ model,
  expecte
@@ -3168,115 +3168,184 @@
 ge, 
-Arrays.asList(CARL, ELLE, FIONA));%0A    %7D%0A%0A    /**%0A     * Parses %7B@code userInput%7D into a %7B@code FindCommand
+expectedModel);%0A        assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());%0A    %7D%0A%0A    /**%0A     * Returns a %7B@code FindCommand%7D with %7B@code predicate
 %7D.%0A 
@@ -3394,24 +3394,47 @@
 and(
-String userInput
+NameContainsKeywordsPredicate predicate
 ) %7B%0A
@@ -3462,32 +3462,16 @@
 ommand =
-%0A               
  new Fin
@@ -3483,81 +3483,17 @@
 and(
-new NameContainsKeywordsPredicate(Arrays.asList(userInput.split(%22%5C%5Cs+%22)))
+predicate
 );%0A 
@@ -3595,787 +3595,252 @@
   * 
-Asserts that %7B@code command%7D is successfully executed, and%3Cbr%3E%0A     *     - the command feedback is equal to %7B@code expectedMessage%7D%3Cbr%3E%0A     *     - the %7B@code FilteredList%3CPerson%3E%7D is equal to %7B@code expectedList%7D%3Cbr%3E
+Parses %7B@code userInput%7D into a %7B@code NameContainsKeywordsPredicate%7D.
 %0A     *
- 
+/%0A
     
-- the %7B@code AddressBook%7D in model remains the same after executing the %7B@code command%7D%0A     */%0A    private void assertCommandSuccess(FindCommand command, String expectedMessage, List%3CPerson%3E expectedList) %7B%0A        AddressBook expectedAddressBook = new AddressBook(model.getAddressBook());%0A        CommandResult commandResult = command.execute();%0A%0A        assertEquals(expectedMessage, commandResult.feedbackToUser);%0A        assertEquals(expectedList, model.getFilteredPersonList());%0A        assertEquals(expectedAddressBook, model.getAddressBook(
+private NameContainsKeywordsPredicate preparePredicate(String userInput) %7B%0A        return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split(%22%5C%5Cs+%22)
 ));%0A

verify entire model state