package savvytodo.logic.commands;

import java.util.List;

import savvytodo.commons.core.Messages;
import savvytodo.logic.commands.exceptions.CommandException;
import savvytodo.logic.parser.CommandTaskDescriptor;
import savvytodo.model.category.UniqueCategoryList;
import savvytodo.model.task.DateTime;
import savvytodo.model.task.Description;
import savvytodo.model.task.Location;
import savvytodo.model.task.Name;
import savvytodo.model.task.Priority;
import savvytodo.model.task.ReadOnlyTask;
import savvytodo.model.task.Recurrence;
import savvytodo.model.task.Status;
import savvytodo.model.task.Task;
import savvytodo.model.task.UniqueTaskList;

//@@author A0140016B
/**
 * Edits the details of an existing task in the task manager.
 */
public class EditCommand extends Command {

    public static final String COMMAND_WORD = "edit";

    public static final String MESSAGE_USAGE = COMMAND_WORD
            + ": Edits the at least one details of the task identified "
            + "by the index number used in the last task listing. "
            + "Existing values will be overwritten by the input values.\n"
            + "Parameters: INDEX (must be a positive integer) "
            + "[NAME] [dt/START_DATE = END_DATE] [l/LOCATION] [p/PRIORITY_LEVEL] "
            + "[r/RECURRING_TYPE NUMBER_OF_RECURRENCE] [c/CATEGORY] [d/DESCRIPTION]...\n"
            + "Example: " + COMMAND_WORD + " 1 c/CS2103 d/Complete group project component";

    public static final String MESSAGE_EDIT_TASK_SUCCESS = "Edited Task: %1$s";
    public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
    public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";

    private final int filteredTaskListIndex;
    private final CommandTaskDescriptor cmdTaskDescriptor;

    /**
     * @param filteredTaskListIndex the index of the task in the filtered task list to edit
     * @param editTaskDescriptor details to edit the task with
     */
    public EditCommand(int filteredTaskListIndex, CommandTaskDescriptor cmdTaskDescriptor) {
        assert filteredTaskListIndex > 0;
        assert cmdTaskDescriptor != null;

        // converts filteredTaskListIndex from one-based to zero-based.
        this.filteredTaskListIndex = filteredTaskListIndex - 1;

        this.cmdTaskDescriptor = new CommandTaskDescriptor(cmdTaskDescriptor);
    }

    @Override
    public CommandResult execute() throws CommandException {
        List<ReadOnlyTask> lastShownList = model.getFilteredTaskList();

        if (filteredTaskListIndex >= lastShownList.size() || filteredTaskListIndex < 0) {
            throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
        }

        ReadOnlyTask taskToEdit = lastShownList.get(filteredTaskListIndex);
        Task editedTask = createEditedTask(taskToEdit, cmdTaskDescriptor);

        try {
            model.updateTask(filteredTaskListIndex, editedTask);
        } catch (UniqueTaskList.DuplicateTaskException dpe) {
            throw new CommandException(MESSAGE_DUPLICATE_TASK);
        }
        model.updateFilteredListToShowAll();
        return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit));
    }

    /**
     * Creates and returns a {@code Task} with the details of {@code taskToEdit}
     * edited with {@code cmdTaskDescriptor}.
     */
    private static Task createEditedTask(ReadOnlyTask taskToEdit,
            CommandTaskDescriptor cmdTaskDescriptor) {
        assert taskToEdit != null;

        Name updatedName = cmdTaskDescriptor.getName().orElseGet(taskToEdit::getName);
        Priority updatedPriority = cmdTaskDescriptor.getPriority()
                .orElseGet(taskToEdit::getPriority);
        Description updatedDescription = cmdTaskDescriptor.getDescription()
                .orElseGet(taskToEdit::getDescription);
        Location updatedLocation = cmdTaskDescriptor.getLocation()
                .orElseGet(taskToEdit::getLocation);
        UniqueCategoryList updatedCategories = cmdTaskDescriptor.getCategories()
                .orElseGet(taskToEdit::getCategories);
        DateTime updatedDateTime = cmdTaskDescriptor.getDateTime()
                .orElseGet(taskToEdit::getDateTime);
        Recurrence updatedRecurrence = cmdTaskDescriptor.getRecurrence()
                .orElseGet(taskToEdit::getRecurrence);
        Status updatedStatus = cmdTaskDescriptor.getStatus().orElseGet(taskToEdit::isCompleted);

        return new Task(updatedName, updatedPriority, updatedDescription, updatedLocation,
                updatedCategories, updatedDateTime, updatedRecurrence);
    }

}

@@ -206,16 +206,57 @@
 riptor;%0A
+import savvytodo.logic.parser.TaskIndex;%0A
 import s
@@ -636,24 +636,63 @@
 .task.Task;%0A
+import savvytodo.model.task.TimeStamp;%0A
 import savvy
@@ -1825,19 +1825,25 @@
 e final 
-int
+TaskIndex
  filtere
@@ -2112,19 +2112,25 @@
 Command(
-int
+TaskIndex
  filtere
@@ -2224,16 +2224,27 @@
 istIndex
+.getIndex()
  %3E 0;%0A  
@@ -2418,12 +2418,8 @@
 ndex
- - 1
 ;%0A%0A 
@@ -2626,16 +2626,33 @@
  = model
+%0A                
 .getFilt
@@ -2664,16 +2664,51 @@
 askList(
+filteredTaskListIndex.getTaskType()
 );%0A%0A    
@@ -2736,16 +2736,31 @@
 istIndex
+.getIndex() - 1
  %3E= last
@@ -2775,16 +2775,32 @@
 t.size()
+%0A               
  %7C%7C filt
@@ -2816,16 +2816,27 @@
 istIndex
+.getIndex()
  %3C 0) %7B%0A
@@ -3006,16 +3006,31 @@
 istIndex
+.getIndex() - 1
 );%0A     
@@ -3164,16 +3164,31 @@
 istIndex
+.getIndex() - 1
 , edited
@@ -4710,16 +4710,72 @@
 leted);%0A
+        TimeStamp timeStamp = taskToEdit.getTimeStamp();
 %0A       
@@ -4923,24 +4923,50 @@
 edRecurrence
+, updatedStatus, timeStamp
 );%0A    %7D%0A%0A%7D%0A
@@ -4964,9 +4964,8 @@
     %7D%0A%0A%7D
-%0A

resolve merge