package arez.downstream;

import gir.Gir;
import gir.GirException;
import gir.delta.Patch;
import gir.git.Git;
import gir.io.Exec;
import gir.ruby.Buildr;
import gir.ruby.Ruby;
import java.util.Collections;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nonnull;

public final class BuildDownstream
{
  public static void main( final String[] args )
  {
    try
    {
      run();
    }
    catch ( final Exception e )
    {
      System.err.println( "Failed command." );
      e.printStackTrace( System.err );
      System.exit( 42 );
    }
  }

  private static void run()
    throws Exception
  {
    Gir.go( () -> Stream
      .of( "arez-browserlocation",
           "arez-dom",
           "arez-promise",
           "arez-mediaquery",
           "arez-networkstatus",
           "arez-spytools",
           "arez-ticker",
           "arez-timeddisposer",
           "arez-when" )
      .forEach( name -> WorkspaceUtil.forEachBranch( name,
                                                     "https://github.com/arez/" + name + ".git",
                                                     Collections.singletonList( "master" ),
                                                     BuildDownstream::buildBranch ) ) );
  }

  private static void buildBranch( @Nonnull final WorkspaceUtil.BuildContext context )
  {
    final String version = WorkspaceUtil.getVersion();

    final String newBranch = context.branch + "-ArezUpgrade-" + version;

    Git.checkout( newBranch, true );
    if ( Git.remoteTrackingBranches().contains( "origin/" + newBranch ) )
    {
      Git.pull();
    }
    Git.clean();

    boolean initialBuildSuccess = false;
    if ( WorkspaceUtil.buildBeforeChanges() )
    {
      Gir.messenger().info( "Building branch " + context.branch + " prior to modifications." );
      try
      {
        WorkspaceUtil.customizeBuildr( context.appDirectory );
        Ruby.buildr( "clean",
                     "package",
                     "PRODUCT_VERSION=",
                     "PREVIOUS_PRODUCT_VERSION=" );
        initialBuildSuccess = true;
      }
      catch ( final GirException e )
      {
        Gir.messenger().info( "Failed to build branch '" + context.branch + "' before modifications.", e );
      }

      Git.resetBranch();
      Git.clean();
    }


    final String group = "org.realityforge.arez";
    final boolean patched =
      Patch.patchAndAddFile( context.appDirectory,
                             context.appDirectory.resolve( "build.yaml" ),
                             c -> Buildr.patchMavenCoordinates( c, group, version ) );
    if ( patched )
    {
      final String message = "Update the '" + group + "' dependencies to version '" + version + "'";
      final Function<String, String> patchFunction = c -> {
        if ( c.contains( "### Unreleased\n\n#" ) )
        {
          return c.replace( "### Unreleased\n\n", "### Unreleased\n\n* " + message + "\n\n" );
        }
        else
        {
          return c.replace( "### Unreleased\n\n", "### Unreleased\n\n* " + message + "\n" );
        }
      };
      Patch.patchAndAddFile( context.appDirectory,
                             context.appDirectory.resolve( "CHANGELOG.md" ),
                             patchFunction );
      Git.commit( message );
    }
    Gir.messenger().info( "Building branch " + context.branch + " after modifications." );
    WorkspaceUtil.customizeBuildr( context.appDirectory );

    try
    {
      /*
       * The process will run through the steps required for a release right up to tagging the source repository.
       * A subsequent call from within release.rake will complete the release process.
       */
      Ruby.buildr( "perform_release",
                   "LAST_STAGE=TagProject",
                   "PRODUCT_VERSION=",
                   "PREVIOUS_PRODUCT_VERSION=" );
      Git.checkout( context.branch );
      Exec.system( "git", "merge", newBranch );
      Git.deleteBranch( newBranch );
    }
    catch ( final GirException e )
    {
      if ( WorkspaceUtil.buildBeforeChanges() && !initialBuildSuccess )
      {
        Gir.messenger().error( "Failed to build branch '" + context.branch + "' before modifications " +
                               "but branch also failed prior to modifications.", e );
      }
      else
      {
        Gir.messenger().error( "Failed to build branch '" + context.branch + "' after modifications.", e );
      }
      throw e;
    }
  }
}

@@ -1416,240 +1416,8 @@
 );%0A%0A
-    final String newBranch = context.branch + %22-ArezUpgrade-%22 + version;%0A%0A    Git.checkout( newBranch, true );%0A    if ( Git.remoteTrackingBranches().contains( %22origin/%22 + newBranch ) )%0A    %7B%0A      Git.pull();%0A    %7D%0A    Git.clean();%0A
 %0A   
@@ -2095,16 +2095,93 @@
 %0A    %7D%0A%0A
+    final String newBranch = WorkspaceUtil.switchToUpgradeBranch( context );%0A
 %0A    fin

Use util method