package arez.downstream;

import gir.sys.SystemProperty;
import java.io.IOException;
import java.util.Properties;
import javax.annotation.Nonnull;
import org.realityforge.gwt.symbolmap.SoycSizeMapsDiff;
import org.realityforge.gwt.symbolmap.SymbolEntryIndexDiff;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class BuildStatsTest
  extends AbstractDownstreamTest
{
  @Test
  public void arez()
    throws Exception
  {
    compareSizesForBranch( "arez", true );
  }

  @Test
  public void dagger()
    throws Exception
  {
    compareSizesForBranch( "dagger", true );
  }

  @Test
  public void sithtracker()
    throws Exception
  {
    compareSizesForBranch( "sithtracker", false );
  }

  private void compareSizesForBranch( @Nonnull final String branch, final boolean includeBranchInFixtureKey )
    throws Exception
  {
    final Properties buildStatistics = loadBuildStatistics();
    final Properties fixtureStatistics = loadFixtureStatistics();

    final long nextVersionFixtureSize =
      extractSize( fixtureStatistics, getNextVersion() + ( includeBranchInFixtureKey ? "." + branch : "" ) );
    final long currentVersionFixtureSize =
      extractSize( fixtureStatistics, getCurrentVersion() + ( includeBranchInFixtureKey ? "." + branch : "" ) );
    final String beforeBuild = branch + "." + "before";
    final String afterBuild = branch + "." + "after";
    final long beforeSize = extractSize( buildStatistics, beforeBuild );
    final long afterSize = extractSize( buildStatistics, afterBuild );

    if ( 0 != nextVersionFixtureSize )
    {
      if ( nextVersionFixtureSize != afterSize )
      {
        reportSymbolDifferences( beforeBuild, afterBuild );
        fail( "Build size after upgrading arez in branch '" + branch + "' does not match the build size " +
              "configured for the next version '" + getNextVersion() + "' which was " + nextVersionFixtureSize +
              ". Actual build size is " + afterSize + ". The statistics can be updated by " +
              "running 'buildr update_downstream_build_stats' and committing the changes if the new size " +
              "is acceptable." );
      }
    }
    else if ( 0 != currentVersionFixtureSize )
    {
      if ( currentVersionFixtureSize != afterSize )
      {
        reportSymbolDifferences( beforeBuild, afterBuild );
        fail( "Build size after upgrading arez in branch '" + branch + "' does not match the build size " +
              "configured for the current version '" + getCurrentVersion() + "' which was " +
              currentVersionFixtureSize + ". No build size was specified for the next version. The actual build " +
              "size is " + afterSize + ". The statistics for the next version can be generated by running " +
              "'buildr update_downstream_build_stats' and committing the changes if the new size is acceptable." );
      }
    }
    else
    {
      if ( beforeSize != afterSize )
      {
        reportSymbolDifferences( beforeBuild, afterBuild );
        fail( "Build size changed after upgrading arez in branch '" + branch + "' from " + beforeSize + " to " +
              afterSize + ". The statistics for the next version can be generated by running " +
              "'buildr update_downstream_build_stats' and committing the changes if the new size is acceptable." );
      }
    }
  }

  private void reportSymbolDifferences( @Nonnull final String beforeBuild, @Nonnull final String afterBuild )
    throws Exception
  {
    final SymbolEntryIndexDiff diff =
      SymbolEntryIndexDiff.diff( getSymbolMapIndex( getArchiveDir(), beforeBuild ),
                                 getSymbolMapIndex( getArchiveDir(), afterBuild ) );
    if ( diff.hasDifferences() )
    {
      System.out.println( "Differences detected in symbols compiled between the " +
                          "two variants " + beforeBuild + " and " + afterBuild );
      System.out.println( diff.printToString() );
    }
    final SoycSizeMapsDiff soycDiff =
      SoycSizeMapsDiff.diff( getSoycSizeMaps( getArchiveDir(), beforeBuild ),
                             getSoycSizeMaps( getArchiveDir(), afterBuild ) );
    if ( soycDiff.hasDifferences() )
    {
      System.out.println( "Differences detected in sizes compiled between the " +
                          "two variants " + beforeBuild + " and " + afterBuild );
      System.out.println( soycDiff.printToString() );
    }
  }

  private long extractSize( @Nonnull final Properties properties,
                            @Nonnull final String prefix )
  {
    return Long.parseLong( properties.getProperty( prefix + ".todomvc.size", "0" ) );
  }

  @Nonnull
  private String getCurrentVersion()
  {
    return SystemProperty.get( "arez.current.version" );
  }

  @Nonnull
  private String getNextVersion()
  {
    return SystemProperty.get( "arez.next.version" );
  }

  @Nonnull
  private Properties loadBuildStatistics()
    throws IOException
  {
    return loadProperties( getWorkDir().resolve( "statistics.properties" ).toFile() );
  }

  @Nonnull
  private Properties loadFixtureStatistics()
    throws IOException
  {
    return loadProperties( getFixtureDir().resolve( "statistics.properties" ).toFile() );
  }
}

@@ -591,32 +591,386 @@
 %22, true );%0A  %7D%0A%0A
+  @Test%0A  public void arez_j2cl()%0A    throws Exception%0A  %7B%0A    if ( WorkspaceUtil.buildJ2clBuilds() )%0A    %7B%0A      compareSizesForBranch( %22arez_maven_j2cl%22, true );%0A    %7D%0A  %7D%0A%0A  @Test%0A  public void dagger_j2cl()%0A    throws Exception%0A  %7B%0A    if ( WorkspaceUtil.buildJ2clBuilds() )%0A    %7B%0A      compareSizesForBranch( %22dagger_maven_j2cl%22, true );%0A    %7D%0A  %7D%0A%0A
   @Test%0A  public

Add some tests for j2cl builds