package study.oauthlab;

import java.util.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.client.*;
import org.springframework.security.oauth2.client.registration.*;
import org.springframework.security.oauth2.client.web.*;
import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestClient;

@Configuration @Profile("client")
class OidcClient {
    @Bean ClientRegistrationRepository registrations(@Value("${lab.issuer}") String issuer) {
        return new InMemoryClientRegistrationRepository(ClientRegistrations.fromIssuerLocation(issuer)
            .registrationId("lab").clientId("lab-client").clientSecret("lab-secret")
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
            .scope("openid","profile","orders.read","orders.write").build());
    }
    @Bean SecurityFilterChain client(HttpSecurity http,ClientRegistrationRepository repo) throws Exception {
        var resolver=new DefaultOAuth2AuthorizationRequestResolver(repo,"/oauth2/authorization");
        resolver.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce());
        http.authorizeHttpRequests(a -> a.requestMatchers("/error").permitAll().anyRequest().authenticated())
            .oauth2Login(o -> o.authorizationEndpoint(a -> a.authorizationRequestResolver(resolver))
                .defaultSuccessUrl("/client/me",true).failureHandler((r,s,e) -> {s.setStatus(401);s.setContentType("application/json");s.getWriter().write("{\"error\":\"oauth2_login_failed\"}");}))
            .oauth2Client(c -> {});
        return http.build();
    }
    @Bean RestClient resourceClient(OAuth2AuthorizedClientManager manager) {
        var interceptor=new OAuth2ClientHttpRequestInterceptor(manager);
        interceptor.setClientRegistrationIdResolver(request -> "lab");
        return RestClient.builder().requestInterceptor(interceptor).build();
    }
    @RestController @Profile("client") static class Endpoints {
        final RestClient http; final String rs;
        Endpoints(RestClient h,@Value("${lab.rs}") String rs) {http=h;this.rs=rs;}
        @GetMapping("/client/me") Map<String,Object> me(@AuthenticationPrincipal OidcUser user) {
            return Map.of("name",user.getSubject(),"issuer",user.getIssuer().toString(),"idTokenValidated",true);
        }
        @GetMapping("/client/resource") String resource() {return http.get().uri(rs+"/jwt/read").retrieve().body(String.class);}
    }
}
