package com.imprimelibros.erp.externalApi;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Map;
import java.util.HashMap;
import java.util.function.Supplier;

@Service
public class skApiClient {

    @Value("${safekat.api.url}")
    private String skApiUrl;

    private final AuthService authService;
    private final RestTemplate restTemplate;

    public skApiClient(AuthService authService) {
        this.authService = authService;
        this.restTemplate = new RestTemplate();
    }

    public String getPrice(Map<String, Object> requestBody) {
        return performWithRetry(() -> {
            String url = this.skApiUrl + "api/calcular";

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setBearerAuth(authService.getToken());

            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);

            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    entity,
                    String.class);

            try {
                Map<String, Object> responseBody = new ObjectMapper().readValue(response.getBody(), Map.class);

                if (responseBody.get("error") == null) {
                    return new ObjectMapper().writeValueAsString(
                            Map.of("data", responseBody.get("data")));
                } else {
                    return "{\"error\": 1}";
                }
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                return "{\"error\": 1}";
            }
        });
    }

    public Integer getMaxSolapas(Map<String, Object> requestBody) {
        try {
            String jsonResponse = performWithRetry(() -> {
                String url = this.skApiUrl + "api/calcular-solapas";

                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                headers.setBearerAuth(authService.getToken()); // token actualizado

                Map<String, Object> data = new HashMap<>();
                data.put("clienteId", requestBody.get("clienteId"));
                data.put("tamanio", requestBody.get("tamanio"));
                data.put("tirada", requestBody.get("tirada"));
                data.put("paginas", requestBody.get("paginas"));
                data.put("paginasColor", requestBody.get("paginasColor"));
                data.put("papelInteriorDiferente", 0);
                data.put("paginasCuadernillo", requestBody.get("paginasCuadernillo"));
                data.put("tipo", requestBody.get("tipo"));
                data.put("isColor", requestBody.get("isColor"));
                data.put("isHq", requestBody.get("isHq"));
                data.put("interior", requestBody.get("interior"));

                HttpEntity<Map<String, Object>> entity = new HttpEntity<>(data, headers);

                ResponseEntity<String> response = restTemplate.exchange(
                        url,
                        HttpMethod.POST,
                        entity,
                        String.class);

                return response.getBody();
            });

            ObjectMapper mapper = new ObjectMapper();
            JsonNode root = mapper.readTree(jsonResponse);

            if (root.get("data") == null || !root.get("data").isInt()) {
                throw new RuntimeException("Respuesta inesperada de calcular-solapas: " + jsonResponse);
            }

            return root.get("data").asInt();

        } catch (JsonProcessingException e) {
            // Fallback al 80% del ancho
            Map<String, Object> tamanio = (Map<String, Object>) requestBody.get("tamanio");
            if (tamanio == null || tamanio.get("ancho") == null)
                throw new RuntimeException("Tamaño no válido en la solicitud: " + requestBody);
            else {
                int ancho = (int) tamanio.get("ancho");
                return (int) Math.floor(ancho * 0.8); // 80% del ancho
            }
        }
    }

    public Double getRetractilado(Map<String, Object> requestBody) {

        String value = performWithRetry(() -> {
            String url = this.skApiUrl + "api/calcular-retractilado";

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setBearerAuth(authService.getToken());

            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);

            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    entity,
                    String.class);

            try {
                Map<String, Object> responseBody = new ObjectMapper().readValue(response.getBody(), Map.class);
                return responseBody.get("data").toString();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                return "0.0"; // Fallback en caso de error
            }
        });
        try {
            return Double.parseDouble(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("Error al parsear el valor de retractilado: " + value, e);
        }
    }

    /******************
     * PRIVATE METHODS
     ******************/
    private String performWithRetry(Supplier<String> request) {
        try {
            return request.get();
        } catch (HttpClientErrorException.Unauthorized e) {
            // Token expirado, renovar y reintentar
            authService.invalidateToken();
            try {
                return request.get(); // segundo intento
            } catch (HttpClientErrorException ex) {
                throw new RuntimeException("La autenticación ha fallado tras renovar el token.", ex);
            }
        }
    }
}
