package dev.sonpx.loyalty.mcp.config;

import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
import static org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal;

import dev.sonpx.loyalty.mcp.reward.client.CampaignClient;
import dev.sonpx.loyalty.mcp.reward.client.CampaignRuleClient;
import java.nio.charset.StandardCharsets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor;
import org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver;
import org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.support.RestClientAdapter;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;

/**
 * Created by SonPhung on Sunday, 19-Jul-2026
 **/
@Slf4j
@Configuration
public class RestClientConfig {

    @Value("${loyalty.core.base-url}")
    private String coreBaseUrl;

    @Bean
    public RestClient rewardRestClient(OAuth2AuthorizedClientManager authorizedClientManager) {
        OAuth2ClientHttpRequestInterceptor oauth2Interceptor =
                new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
        oauth2Interceptor.setClientRegistrationIdResolver(new RequestAttributeClientRegistrationIdResolver());
        oauth2Interceptor.setPrincipalResolver(new RequestAttributePrincipalResolver());

        return RestClient.builder()
                .baseUrl(coreBaseUrl + "/svc/reward")
                .requestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
                .requestInterceptor((request, body, execution) -> {
                    clientRegistrationId("keycloak").accept(request.getAttributes());
                    principal("loyalty-service").accept(request.getAttributes());
                    
                    log.info("MCP-Agent Call API [Request] -> {} {}", request.getMethod(), request.getURI());
                    if (body.length > 0) {
                        log.info("MCP-Agent Call API [Request Body] -> {}", new String(body, StandardCharsets.UTF_8));
                    }
                    
                    ClientHttpResponse response = oauth2Interceptor.intercept(request, body, execution);
                    
                    log.info("MCP-Agent Call API [Response Status] <- {}", response.getStatusCode());
                    if (response.getBody() != null) {
                        log.info("MCP-Agent Call API [Response Body] <- {}", StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8));
                    }
                    
                    return response;
                })
                .defaultStatusHandler(
                        HttpStatusCode::isError,
                        (request, response) -> {
                            throw new RuntimeException("API Error: HTTP Status " + response.getStatusCode() + " Body: " + new String(response.getBody().readAllBytes()));
                        }
                )
                .build();
    }


    @Bean
    public HttpServiceProxyFactory rewardHttpServiceProxyFactory(RestClient rewardRestClient) {
        return HttpServiceProxyFactory.builderFor(RestClientAdapter.create(rewardRestClient))
                .customArgumentResolver(new PageableArgumentResolver())
                .customArgumentResolver(new PojoArgumentResolver())
                .build();
    }

    @Bean
    public CampaignClient campaignClient(HttpServiceProxyFactory rewardHttpServiceProxyFactory) {
        return rewardHttpServiceProxyFactory.createClient(CampaignClient.class);
    }

    @Bean
    public CampaignRuleClient campaignRuleClient(HttpServiceProxyFactory rewardHttpServiceProxyFactory) {
        return rewardHttpServiceProxyFactory.createClient(CampaignRuleClient.class);
    }

    @Bean
    public dev.sonpx.loyalty.mcp.reward.client.PoolDefinitionClient poolDefinitionClient(HttpServiceProxyFactory rewardHttpServiceProxyFactory) {
        return rewardHttpServiceProxyFactory.createClient(dev.sonpx.loyalty.mcp.reward.client.PoolDefinitionClient.class);
    }

    @Bean
    public dev.sonpx.loyalty.mcp.reward.client.CounterDefinitionClient counterDefinitionClient(HttpServiceProxyFactory rewardHttpServiceProxyFactory) {
        return rewardHttpServiceProxyFactory.createClient(dev.sonpx.loyalty.mcp.reward.client.CounterDefinitionClient.class);
    }

    @Bean
    public dev.sonpx.loyalty.mcp.reward.client.DeductionSequenceClient deductionSequenceClient(HttpServiceProxyFactory rewardHttpServiceProxyFactory) {
        return rewardHttpServiceProxyFactory.createClient(dev.sonpx.loyalty.mcp.reward.client.DeductionSequenceClient.class);
    }

    @Bean
    public dev.sonpx.loyalty.mcp.reward.client.TransactionCodeClient transactionCodeClient(HttpServiceProxyFactory rewardHttpServiceProxyFactory) {
        return rewardHttpServiceProxyFactory.createClient(dev.sonpx.loyalty.mcp.reward.client.TransactionCodeClient.class);
    }
}
