package org.robolectric.annotation.processing.validator;

import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
import static org.robolectric.annotation.processing.RobolectricProcessorTest.DEFAULT_OPTS;

import com.google.common.collect.ImmutableList;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import com.google.testing.compile.CompileTester;
import com.google.testing.compile.CompileTester.LineClause;
import com.google.testing.compile.CompileTester.SuccessfulCompilationClause;
import com.google.testing.compile.CompileTester.UnsuccessfulCompilationClause;
import com.google.testing.compile.JavaFileObjects;
import javax.tools.JavaFileObject;
import org.robolectric.annotation.processing.RobolectricProcessor;

public final class SingleClassSubject extends Subject<SingleClassSubject, String> {

  public static SubjectFactory<SingleClassSubject, String> singleClass() {

    return new SubjectFactory<SingleClassSubject, String>() {

      @Override
      public SingleClassSubject getSubject(FailureStrategy failureStrategy, String source) {
        return new SingleClassSubject(failureStrategy, source);
      }
    };
  }


  JavaFileObject source;
  CompileTester tester;
  
  public SingleClassSubject(FailureStrategy failureStrategy, String subject) {
    super(failureStrategy, subject);
    source = JavaFileObjects.forResource(Utils.toResourcePath(subject));
    tester = assertAbout(javaSources())
      .that(ImmutableList.of(source, Utils.ROBO_SOURCE, Utils.SHADOW_EXTRACTOR_SOURCE))
      .processedWith(new RobolectricProcessor(DEFAULT_OPTS));
  }

  public SuccessfulCompilationClause compilesWithoutError() {
    try {
      return tester.compilesWithoutError();
    } catch (AssertionError e) {
      failWithRawMessage(e.getMessage());
    }
    return null;
  }
  
  public SingleFileClause failsToCompile() {
    try {
      return new SingleFileClause(tester.failsToCompile(), source);
    } catch (AssertionError e) {
      failWithRawMessage(e.getMessage());
    }
    return null;
  }
  
  final class SingleFileClause implements CompileTester.ChainingClause<SingleFileClause> {

    UnsuccessfulCompilationClause unsuccessful;
    JavaFileObject source;
    
    public SingleFileClause(UnsuccessfulCompilationClause unsuccessful, JavaFileObject source) {
      this.unsuccessful = unsuccessful;
      this.source = source;
    }
    
    public SingleLineClause withErrorContaining(final String messageFragment) {
      try {
        return new SingleLineClause(unsuccessful.withErrorContaining(messageFragment).in(source));
      } catch (AssertionError e) {
        failWithRawMessage(e.getMessage());
      }
      return null;
    }

    public SingleFileClause withNoErrorContaining(final String messageFragment) {
      try {
        unsuccessful.withErrorContaining(messageFragment);
      } catch (AssertionError e) {
        return this;
      }
      failWithRawMessage(
          "Shouldn't have found any errors containing " + messageFragment + ", but we did");

      return this;
    }
    
    @Override
    public SingleFileClause and() {
      return this;
    }

    final class SingleLineClause implements CompileTester.ChainingClause<SingleFileClause> {

      LineClause lineClause;
      
      public SingleLineClause(LineClause lineClause) {
        this.lineClause = lineClause;
      }
      
      public CompileTester.ChainingClause<SingleFileClause> onLine(long lineNumber) {
        try {
          lineClause.onLine(lineNumber);
          return new CompileTester.ChainingClause<SingleFileClause>() {
            @Override
            public SingleFileClause and() {
              return SingleFileClause.this;
            }
          };
        } catch (AssertionError e) {
          failWithRawMessage(e.getMessage());
        }
        return null;
      }
      
      @Override
      public SingleFileClause and() {
        return SingleFileClause.this;
      }
    
    }
  }
}

@@ -366,24 +366,24 @@
 .Failure
-Strategy
+Metadata
 ;%0Aimport
@@ -420,55 +420,8 @@
 ct;%0A
-import com.google.common.truth.SubjectFactory;%0A
 impo
@@ -935,32 +935,33 @@
 c static Subject
+.
 Factory%3CSingleCl
@@ -1012,254 +1012,39 @@
 urn 
-new SubjectFactory%3CSingleClassSubject, String%3E() %7B%0A%0A      @Override%0A      public SingleClassSubject getSubject(FailureStrategy failureStrategy, String source) %7B%0A        return new SingleClassSubject(failureStrategy, source);%0A      %7D%0A    %7D;%0A  %7D
+SingleClassSubject::new;%0A  %7D%0A
 %0A%0A
-%0A
   Ja
@@ -1130,32 +1130,32 @@
 lure
-Strategy failureStrategy
+Metadata failureMetadata
 , St
@@ -1191,16 +1191,16 @@
 lure
-Strategy
+Metadata
 , su

Replace truth.FailureStrategy with truth.FailureMetadata in custom Subjects.