package com.honey.honey.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.media.MediaType;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Central place for all OpenAPI request/response examples.
 * Examples are added to components and attached to the relevant operations
 * so controllers stay free of large example payloads.
 */
@Component
public class OpenApiExamplesCustomizer implements GlobalOpenApiCustomizer {

    public static final String EXAMPLE_CURRENT_USER_RESPONSE = "CurrentUserResponse";
    public static final String EXAMPLE_LANGUAGE_REQUEST = "LanguageRequest";
    public static final String EXAMPLE_DEPOSIT_METHODS_RESPONSE = "DepositMethodsResponse";
    public static final String EXAMPLE_DEPOSIT_ADDRESS_REQUEST = "DepositAddressRequest";
    public static final String EXAMPLE_DEPOSIT_ADDRESS_RESPONSE = "DepositAddressResponse";

    @Override
    public void customise(OpenAPI openAPI) {
        ensureComponents(openAPI);
        addCurrentUserResponseExample(openAPI);
        attachCurrentUserExampleToEndpoint(openAPI);
        addLanguageRequestExample(openAPI);
        attachLanguageExampleToEndpoint(openAPI);
        addDepositMethodsResponseExample(openAPI);
        attachDepositMethodsExampleToEndpoint(openAPI);
        addDepositAddressRequestExample(openAPI);
        addDepositAddressResponseExample(openAPI);
        attachDepositAddressExamplesToEndpoint(openAPI);
    }

    private void ensureComponents(OpenAPI openAPI) {
        if (openAPI.getComponents() == null) {
            openAPI.setComponents(new io.swagger.v3.oas.models.Components());
        }
        if (openAPI.getComponents().getExamples() == null) {
            openAPI.getComponents().setExamples(new LinkedHashMap<>());
        }
    }

    private void addCurrentUserResponseExample(OpenAPI openAPI) {
        Map<String, Object> value = new LinkedHashMap<>();
        value.put("id", 2900001);
        value.put("telegram_id", 12851929);
        value.put("username", "theboy");
        value.put("screenName", "The Boy");
        value.put("dateReg", 1772897273);
        value.put("ip", "165.165.165.165");
        value.put("balanceA", 10000);
        value.put("balanceB", 10000);
        value.put("avatarUrl", "/avatars/0/0/1/06c98267.png?v=1772897273");
        value.put("languageCode", "EN");
        value.put("paymentEnabled", true);
        value.put("payoutEnabled", true);
        value.put("banned", false);
        value.put("depositCount", 0);

        Example example = new Example();
        example.setSummary("Current user response");
        example.setValue(value);
        openAPI.getComponents().getExamples().put(EXAMPLE_CURRENT_USER_RESPONSE, example);
    }

    private void attachCurrentUserExampleToEndpoint(OpenAPI openAPI) {
        var paths = openAPI.getPaths();
        if (paths == null) return;

        var pathItem = paths.get("/api/users/current");
        if (pathItem == null || pathItem.getGet() == null) return;

        var responses = pathItem.getGet().getResponses();
        if (responses == null) return;

        var response200 = responses.get("200");
        if (response200 == null || response200.getContent() == null) return;

        MediaType json = response200.getContent().get("application/json");
        if (json == null) return;

        Example example = (Example) openAPI.getComponents().getExamples().get(EXAMPLE_CURRENT_USER_RESPONSE);
        if (example != null) {
            json.setExamples(Map.of("success", example));
        }
    }

    private void addLanguageRequestExample(OpenAPI openAPI) {
        Map<String, Object> value = new LinkedHashMap<>();
        value.put("languageCode", "PL");
        Example example = new Example();
        example.setSummary("Update language request");
        example.setValue(value);
        openAPI.getComponents().getExamples().put(EXAMPLE_LANGUAGE_REQUEST, example);
    }

    private void attachLanguageExampleToEndpoint(OpenAPI openAPI) {
        var paths = openAPI.getPaths();
        if (paths == null) return;
        var pathItem = paths.get("/api/users/language");
        if (pathItem == null || pathItem.getPut() == null) return;
        var requestBody = pathItem.getPut().getRequestBody();
        if (requestBody == null || requestBody.getContent() == null) return;
        MediaType json = requestBody.getContent().get("application/json");
        if (json == null) return;
        Example example = (Example) openAPI.getComponents().getExamples().get(EXAMPLE_LANGUAGE_REQUEST);
        if (example != null) {
            json.setExamples(Map.of("PL", example));
        }
    }

    private void addDepositMethodsResponseExample(OpenAPI openAPI) {
        Map<String, Object> value = new LinkedHashMap<>();
        value.put("minimumDeposit", 2.50);
        value.put("activeMethods", List.of(
                Map.of(
                        "pid", 235,
                        "name", "TON",
                        "network", "TON",
                        "example", "UQAm3JwwV_wMgmJ05AzHqtlHAdkyJt58N-JHV2Uhf80hOEKD",
                        "minDepositSum", 2.50
                ),
                Map.of(
                        "pid", 90,
                        "name", "TRON",
                        "network", "TRC20",
                        "example", "TMQqX43PAMZPXPxX6Qj1fCyeiMWLgW35yF",
                        "minDepositSum", 2.50
                ),
                Map.of(
                        "pid", 10,
                        "name", "Bitcoin",
                        "network", "BTC",
                        "example", "131qX9kauDpCGyn2MfAFwHcrrVk7JTLAYj",
                        "minDepositSum", 2.50
                )
        ));
        Example example = new Example();
        example.setSummary("Deposit methods response");
        example.setValue(value);
        openAPI.getComponents().getExamples().put(EXAMPLE_DEPOSIT_METHODS_RESPONSE, example);
    }

    private void attachDepositMethodsExampleToEndpoint(OpenAPI openAPI) {
        var paths = openAPI.getPaths();
        if (paths == null) return;
        var pathItem = paths.get("/api/payments/deposit-methods");
        if (pathItem == null || pathItem.getGet() == null) return;
        var responses = pathItem.getGet().getResponses();
        if (responses == null) return;
        var response200 = responses.get("200");
        if (response200 == null || response200.getContent() == null) return;
        MediaType json = response200.getContent().get("application/json");
        if (json == null) return;
        Example example = (Example) openAPI.getComponents().getExamples().get(EXAMPLE_DEPOSIT_METHODS_RESPONSE);
        if (example != null) {
            json.setExamples(Map.of("success", example));
        }
    }

    private void addDepositAddressRequestExample(OpenAPI openAPI) {
        Map<String, Object> value = new LinkedHashMap<>();
        value.put("pid", 235);
        value.put("usdAmount", 3);
        Example example = new Example();
        example.setSummary("Deposit address request");
        example.setValue(value);
        openAPI.getComponents().getExamples().put(EXAMPLE_DEPOSIT_ADDRESS_REQUEST, example);
    }

    private void addDepositAddressResponseExample(OpenAPI openAPI) {
        Map<String, Object> value = new LinkedHashMap<>();
        value.put("address", "UQAY95OcdK3Cu-SEflKsaeN7y463BASTmnY9OUdRLJK-FDxc");
        value.put("amountCoins", "2.234549");
        value.put("name", "TON");
        value.put("network", "-");
        value.put("psId", 235);
        value.put("minAmount", 2.5);
        Example example = new Example();
        example.setSummary("Deposit address response");
        example.setValue(value);
        openAPI.getComponents().getExamples().put(EXAMPLE_DEPOSIT_ADDRESS_RESPONSE, example);
    }

    private void attachDepositAddressExamplesToEndpoint(OpenAPI openAPI) {
        var paths = openAPI.getPaths();
        if (paths == null) return;
        var pathItem = paths.get("/api/payments/deposit-address");
        if (pathItem == null || pathItem.getPost() == null) return;

        var requestBody = pathItem.getPost().getRequestBody();
        if (requestBody != null && requestBody.getContent() != null) {
            MediaType reqJson = requestBody.getContent().get("application/json");
            if (reqJson != null) {
                Example reqExample = (Example) openAPI.getComponents().getExamples().get(EXAMPLE_DEPOSIT_ADDRESS_REQUEST);
                if (reqExample != null) {
                    reqJson.setExamples(Map.of("example", reqExample));
                }
            }
        }

        var responses = pathItem.getPost().getResponses();
        if (responses != null) {
            var response200 = responses.get("200");
            if (response200 != null && response200.getContent() != null) {
                MediaType resJson = response200.getContent().get("application/json");
                if (resJson != null) {
                    Example resExample = (Example) openAPI.getComponents().getExamples().get(EXAMPLE_DEPOSIT_ADDRESS_RESPONSE);
                    if (resExample != null) {
                        resJson.setExamples(Map.of("success", resExample));
                    }
                }
            }
        }
    }
}
