package com.project.whatsappchatbot.service;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestTemplate;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

@Service
public class LaravelTokenService {


    @Value("${laravel.rsa.private.key}")
    private String ecPrivateKeyPem;

    @Value("${laravel.hmac.secret}")
    private String hmacSecretKey;

    @Value("${laravel.api.url}")
    private String laravelApiUrl;

    @Async
    public CompletableFuture<ResponseEntity<String>> getJwtFromLaravel(String phone) {
        try {
            String route = "get-access-token";
            String inputOfSignature = "bf-hello";

            String signature = generateEcSignature(inputOfSignature, ecPrivateKeyPem);
            String hash = hmacSha256(hmacSecretKey, route);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            headers.set("X-Signed-Request", "bf-hello");
            headers.set("X-Signature", signature);

            MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
            form.add("route", route);
            form.add("hash", hash);
            form.add("phone", phone);

            HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(form, headers);
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.postForEntity(laravelApiUrl, entity, String.class);
            return CompletableFuture.completedFuture(response);

        } catch (RestClientResponseException ex) {
            ResponseEntity<String> errorResponse = new ResponseEntity<>(
                    ex.getResponseBodyAsString(),
                    ex.getResponseHeaders(),
                    HttpStatus.valueOf(ex.getRawStatusCode())
            );
            return CompletableFuture.completedFuture(errorResponse);
        } catch (Exception e) {
            throw new RuntimeException("Request to Laravel failed", e);
        }
    }

    private static String hmacSha256(String key, String data) {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            byte[] hashBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));

            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();

        } catch (Exception e) {
            throw new RuntimeException("HMAC generation failed", e);
        }
    }

    private String generateEcSignature(String input, String ecPrivateKeyPem) {
        try {
            String cleanedKey = ecPrivateKeyPem
                    .replaceAll("-----BEGIN EC PRIVATE KEY-----", "")
                    .replaceAll("-----END EC PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            System.out.println("Key length: " + cleanedKey.length());
            System.out.println("Key length % 4 = " + (cleanedKey.length() % 4));

            while (cleanedKey.length() % 4 != 0) {
                cleanedKey += "=";
            }

            byte[] keyBytes = Base64.getDecoder().decode(cleanedKey);

            byte[] privateKeyBytes = new byte[32];
            System.arraycopy(keyBytes, 7, privateKeyBytes, 0, 32);

            BigInteger privateKeyValue = new BigInteger(1, privateKeyBytes);

            AlgorithmParameters params = AlgorithmParameters.getInstance("EC");
            params.init(new ECGenParameterSpec("secp256r1"));
            ECParameterSpec ecParams = params.getParameterSpec(ECParameterSpec.class);

            ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(privateKeyValue, ecParams);

            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

            Signature signature = Signature.getInstance("SHA256withECDSA");
            signature.initSign(privateKey);
            signature.update(input.getBytes(StandardCharsets.UTF_8));
            byte[] signed = signature.sign();

            return Base64.getEncoder().encodeToString(signed);
        } catch (Exception e) {
            System.err.println("Detailed error: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("EC signature failed", e);
        }
    }

}
