package io.digdag.server;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import io.digdag.client.config.Config;
import org.immutables.value.Value;

import javax.annotation.Nullable;
import javax.ws.rs.container.ContainerRequestContext;

import java.util.Map;

import static org.immutables.value.Value.Style.ImplementationVisibility.PACKAGE;

public interface Authenticator
{
    @Value.Immutable
    @Value.Style(visibility = PACKAGE)
    @JsonSerialize(as = ImmutableResult.class)
    @JsonDeserialize(as = ImmutableResult.class)
    interface Result
    {
        static Result accept(int siteId)
        {
            return accept(siteId, Optional.absent());
        }

        static Result accept(int siteId, Config userInfo)
        {
            return accept(siteId, Optional.fromNullable(userInfo));
        }

        static Result accept(int siteId, Optional<Config> userInfo)
        {
            return ImmutableResult.builder()
                    .siteId(siteId)
                    .userInfo(userInfo)
                    .build();
        }

        static Result reject(String message)
        {
            return ImmutableResult.builder()
                    .siteId(0)
                    .errorMessage(message)
                    .userInfo(Optional.absent())
                    .build();
        }

        default boolean isAccepted()
        {
            return getErrorMessage() == null;
        }

        int getSiteId();

        @Value.Default
        default boolean isAdmin() {
            return false;
        }

        @Nullable
        String getErrorMessage();

        Optional<Config> getUserInfo();

        Optional<Supplier<Map<String, String>>> getSecrets();

        static Builder builder() {
            return ImmutableResult.builder();
        }

        interface Builder {
            Builder siteId(int siteId);
            Builder userInfo(Config userInfo);
            Builder secrets(Supplier<Map<String, String>> secrets);
            Builder isAdmin(boolean admin);
            Builder errorMessage(String errorMessage);
            Result build();
        }
    }

    Result authenticate(ContainerRequestContext requestContext);
}

@@ -190,16 +190,61 @@
 tional;%0A
+import com.google.common.base.Preconditions;%0A
 import c
@@ -296,28 +296,29 @@
 dag.
-client.config.Config
+spi.AuthenticatedUser
 ;%0Aim
@@ -355,42 +355,8 @@
 e;%0A%0A
-import javax.annotation.Nullable;%0A
 impo
@@ -760,308 +760,69 @@
 ept(
-int siteId)%0A        %7B%0A            return accept(siteId, Optional.absent());%0A        %7D%0A%0A        static Result accept(int siteId, Config userInfo)%0A        %7B%0A            return accept(siteId, Optional.fromNullable(userInfo));%0A        %7D%0A%0A        static Result accept(int siteId, Optional%3CConfig
+AuthenticatedUser user, Supplier%3CMap%3CString, String%3E
 %3E 
-u
 se
-rInfo
+crets
 )%0A  
@@ -900,20 +900,22 @@
   .s
-iteId(siteId
+ecrets(secrets
 )%0A  
@@ -937,25 +937,30 @@
    .
-userInfo
+authenticatedUser
 (user
-Info
 )%0A  
@@ -1102,39 +1102,8 @@
 r()%0A
-                    .siteId(0)%0A
     
@@ -1145,57 +1145,8 @@
 ge)%0A
-                    .userInfo(Optional.absent())%0A
     
@@ -1248,16 +1248,17 @@
  return 
+!
 getError
@@ -1270,16 +1270,20 @@
 ge()
- == null
+.isPresent()
 ;%0A  
@@ -1303,84 +1303,53 @@
     
-int getSiteId();%0A%0A        @Value.Default%0A        default boolean isAdmin() %7B
+@Value.Check%0A        default void checkNull()
 %0A   
@@ -1357,274 +1357,218 @@
     
+%7B%0A
     
-return false;%0A        %7D%0A%0A        @Nullable%0A        String getErrorMessage();%0A%0A        Optional%3CConfig%3E getUserInfo();%0A%0A        Optional%3CSupplier%3CMap%3CString, String%3E%3E%3E getSecrets();%0A%0A        static Builder builder() %7B%0A            return ImmutableResult.builder();
+        if (isAccepted()) %7B%0A                // authenticated user%0A                Preconditions.checkState(getSecrets().isPresent() && getAuthenticatedUser().isPresent());%0A            %7D%0A            else %7B
 %0A   
@@ -1572,27 +1572,24 @@
         
-%7D%0A%0A
         
 interfac
@@ -1584,143 +1584,220 @@
     
-interface Builder %7B%0A            Builder siteId(int siteId);%0A            Builder userInfo(Config userInfo);%0A            Builder secrets(
+// error message%0A                Preconditions.checkState(!getSecrets().isPresent() %7C%7C !getAuthenticatedUser().isPresent());%0A            %7D%0A        %7D%0A%0A        Optional%3CString%3E getErrorMessage();%0A%0A        Optional%3C
 Supp
@@ -1825,30 +1825,33 @@
 ng%3E%3E
- s
+%3E getS
 ecrets
+(
 );%0A
-   
+%0A
         
  Bui
@@ -1850,133 +1850,59 @@
     
- Builder isAdmin(boolean admin);%0A            Builder errorMessage(String errorMessage);%0A            Result build();%0A        %7D
+Optional%3CAuthenticatedUser%3E getAuthenticatedUser();
 %0A   

Refactor and modify to use spi.AuthenticatedUser in server.Authenticator