/**
 * @ Author: Harry
 * @ Create Time: 2025-06-25
 * @ Modified by: Harry
 * @ Modified time: 2025-06-30
 * @ Description: Configuration for Kinde integration with custom Gson configuration to handle unknown fields.
 */

package ca.trolet.datareplicationservice.config;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.kinde.KindeAdminSession;
import com.kinde.KindeAdminSessionBuilder;
import com.kinde.KindeClient;
import com.kinde.KindeClientBuilder;
import org.openapitools.client.ApiClient;
import org.openapitools.client.JSON;
import org.openapitools.client.api.UsersApi;
import org.openapitools.client.model.UsersResponseUsersInner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Type;

@Configuration
public class KindeConfig {

    @Value("${kinde.domain}")
    private String kindeDomain;

    @Value("${kinde.management.client-id}")
    private String kindeClientId;

    @Value("${kinde.management.client-secret}")
    private String kindeClientSecret;

    @Value("${kinde.audience}")
    private String kindeAudience;

    @Bean
    public KindeClient kindeClient() {
        return KindeClientBuilder.builder()
                .domain(kindeDomain)
                .clientId(kindeClientId)
                .clientSecret(kindeClientSecret)
                .addScope("openid")
                .addAudience(kindeAudience)
                .build();
    }

    /**
     * Custom Gson configuration to handle unknown fields gracefully
     */
    @Bean
    public Gson customGson() {
        return new GsonBuilder()
                .setLenient()
                // Register a custom deserializer for UsersResponseUsersInner to handle unknown fields
                .registerTypeAdapter(UsersResponseUsersInner.class, new JsonDeserializer<UsersResponseUsersInner>() {
                    @Override
                    public UsersResponseUsersInner deserialize(JsonElement json, Type typeOfT,
                                                               JsonDeserializationContext context) throws JsonParseException {
                        // Create a new Gson instance without the custom deserializer to avoid infinite recursion
                        Gson gson = new GsonBuilder().setLenient().create();

                        // Remove the problematic 'full_name' field from the JSON before deserializing
                        if (json.isJsonObject() && json.getAsJsonObject().has("full_name")) {
                            json.getAsJsonObject().remove("full_name");
                        }

                        return gson.fromJson(json, UsersResponseUsersInner.class);
                    }
                })
                .create();
    }

    @Bean
    public ApiClient kindeApiClient(KindeClient kindeClient, Gson customGson) {
        KindeAdminSession kindeAdminSession = KindeAdminSessionBuilder.builder()
                .client(kindeClient)
                .build();

        ApiClient apiClient = kindeAdminSession.initClient();

        // Configure the API client to use our custom Gson
        try {
            // Try to replace the JSON processor with our custom Gson
            JSON json = new JSON();
            json.setGson(customGson);
            apiClient.setJSON(json);

            System.out.println("Successfully configured custom Gson for Kinde API client");
        } catch (Exception e) {
            System.err.println("Could not configure custom Gson: " + e.getMessage());
            e.printStackTrace();
        }

        return apiClient;
    }

    @Bean
    public UsersApi usersApi(ApiClient apiClient) {
        return new UsersApi(apiClient);
    }
}