package com.beijunyi.parallelgit.filesystem.commands;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collections;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.beijunyi.parallelgit.filesystem.GfsState;
import com.beijunyi.parallelgit.filesystem.GfsStatusProvider;
import com.beijunyi.parallelgit.filesystem.GitFileSystem;
import com.beijunyi.parallelgit.filesystem.exceptions.NoBranchException;
import com.beijunyi.parallelgit.filesystem.exceptions.NoHeadCommitException;
import com.beijunyi.parallelgit.utils.CommitUtils;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;

import static com.beijunyi.parallelgit.utils.CommitUtils.getCommit;

public class GfsCreateStashCommand extends GfsCommand<GfsCreateStashCommand.Result> {

  private static final String DEFAULT_MESSAGE_FORMAT = "index on {0}: {1} {2}";

  private String branch;
  private String message;
  private PersonIdent committer;
  private AnyObjectId parent;

  public GfsCreateStashCommand(@Nonnull GitFileSystem gfs) {
    super(gfs);
  }

  @Nonnull
  @Override
  protected GfsState getCommandState() {
    return GfsState.CREATING_STASH;
  }

  @Nonnull
  public GfsCreateStashCommand setMessage(@Nonnull String message) {
    this.message = message;
    return this;
  }

  @Nonnull
  public GfsCreateStashCommand setCommitter(@Nonnull PersonIdent committer) {
    this.committer = committer;
    return this;
  }

  @Nonnull
  public GfsCreateStashCommand setParent(@Nonnull AnyObjectId parent) {
    this.parent = parent;
    return this;
  }

  @Nonnull
  @Override
  protected GfsCreateStashCommand.Result doExecute(@Nonnull GfsStatusProvider.Update update) throws IOException {
    prepareBranch();
    prepareCommitter();
    prepareParent();
    prepareMessage();
    AnyObjectId resultTree = gfs.flush();
    if(parent != null && parent.equals(resultTree))
      return Result.noChange();
    RevCommit resultCommit = CommitUtils.createCommit(message, resultTree, committer, committer, Collections.singletonList(parent), repo);
    resetHead();
    return Result.success(resultCommit);
  }

  private void prepareMessage() throws IOException {
    if(message == null) {
      message = MessageFormat.format(DEFAULT_MESSAGE_FORMAT, branch, parent.abbreviate(7).name(), getCommit(parent, repo).getShortMessage());
    }
  }

  private void prepareBranch() {
    if(!status.isAttached())
      throw new NoBranchException();
    branch = Repository.shortenRefName(status.branch());
  }

  private void prepareCommitter() {
    if(committer == null)
      committer = new PersonIdent(repo);
  }

  private void prepareParent() {
    if(!status.isInitialized())
      throw new NoHeadCommitException();
    parent = status.commit();
  }

  private void resetHead() {

  }

  public enum Status {
    COMMITTED,
    NO_CHANGE
  }

  public static class Result implements GfsCommandResult {

    private final Status status;
    private final RevCommit commit;

    public Result(@Nonnull Status status, @Nullable RevCommit commit) {
      this.status = status;
      this.commit = commit;
    }

    @Override
    public boolean isSuccessful() {
      return false;
    }

    @Nonnull
    public static Result success(@Nonnull RevCommit commit) {
      return new Result(Status.COMMITTED, commit);
    }

    @Nonnull
    public static Result noChange() {
      return new Result(Status.NO_CHANGE, null);
    }

  }

}

@@ -932,32 +932,38 @@
  String DEFAULT_
+INDEX_
 MESSAGE_FORMAT =
@@ -992,52 +992,189 @@
 %7D%22;%0A
-%0A  private String branch;%0A  private String m
+  private static final String DEFAULT_WORKING_DIR_MESSAGE_FORMAT = %22WIP on %7B0%7D: %7B1%7D %7B2%7D%22;%0A%0A  private String branch;%0A  private String indexMessage;%0A  private String workingDirectoryM
 essa
@@ -1470,19 +1470,21 @@
 Command 
-set
+index
 Message(
@@ -1499,17 +1499,22 @@
  String 
-m
+indexM
 essage) 
@@ -1524,17 +1524,22 @@
    this.
-m
+indexM
 essage =
@@ -1539,17 +1539,22 @@
 ssage = 
-m
+indexM
 essage;%0A
@@ -1621,12 +1621,9 @@
 and 
-setC
+c
 ommi
@@ -1761,12 +1761,9 @@
 and 
-setP
+p
 aren
@@ -2049,32 +2049,68 @@
 t();%0A    prepare
+IndexMessage();%0A    prepareDirectory
 Message();%0A    A
@@ -2284,17 +2284,22 @@
 eCommit(
-m
+indexM
 essage, 
@@ -2459,16 +2459,21 @@
  prepare
+Index
 Message(
@@ -2502,17 +2502,22 @@
 %0A    if(
-m
+indexM
 essage =
@@ -2527,18 +2527,21 @@
 ull)
- %7B
 %0A      
-m
+indexM
 essa
@@ -2574,16 +2574,22 @@
 DEFAULT_
+INDEX_
 MESSAGE_
@@ -2679,19 +2679,290 @@
 e());%0A  
-  %7D
+%7D%0A%0A  private void prepareDirectoryMessage() throws IOException %7B%0A    if(workingDirectoryMessage == null)%0A      workingDirectoryMessage = MessageFormat.format(DEFAULT_WORKING_DIR_MESSAGE_FORMAT, branch, parent.abbreviate(7).name(), getCommit(parent, repo).getShortMessage());
 %0A  %7D%0A%0A  

create stash command refactoring wip