package com.rj.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rj.config.LbAssessmentDingTalkProperties;
import com.rj.service.DingTalkRobotService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class DingTalkRobotServiceImpl implements DingTalkRobotService {

    private static final String SEND_URL = "https://oapi.dingtalk.com/robot/send";

    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    private final LbAssessmentDingTalkProperties properties;

    public DingTalkRobotServiceImpl(RestTemplate restTemplate,
                                    ObjectMapper objectMapper,
                                    LbAssessmentDingTalkProperties properties) {
        this.restTemplate = restTemplate;
        this.objectMapper = objectMapper;
        this.properties = properties;
    }

    @Override
    public void sendText(String content) {
        if (!properties.isEnabled()) {
            throw new IllegalStateException("钉钉机器人发送未启用，请在配置中设置 lb.assessment-apply.dingtalk.enabled=true");
        }
        if (!StringUtils.hasText(properties.getAccessToken())) {
            throw new IllegalStateException("未配置钉钉机器人 access-token（lb.assessment-apply.dingtalk.access-token）");
        }
        if (!StringUtils.hasText(content)) {
            throw new IllegalArgumentException("发送内容不能为空");
        }

        String url = buildWebhookUrl();
        Map<String, Object> body = new HashMap<>();
        body.put("msgtype", "text");
        Map<String, String> text = new HashMap<>();
        text.put("content", content);
        body.put("text", text);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);

        ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
        parseResponse(response.getBody());
    }

    private String buildWebhookUrl() {
        StringBuilder url = new StringBuilder(SEND_URL)
                .append("?access_token=")
                .append(properties.getAccessToken().trim());
        if (StringUtils.hasText(properties.getSecret())) {
            long timestamp = System.currentTimeMillis();
            String sign = sign(timestamp, properties.getSecret().trim());
            url.append("&timestamp=").append(timestamp).append("&sign=").append(sign);
        }
        return url.toString();
    }

    private static String sign(long timestamp, String secret) {
        try {
            String stringToSign = timestamp + "\n" + secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
            return URLEncoder.encode(Base64.getEncoder().encodeToString(signData), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new IllegalStateException("钉钉加签失败：" + e.getMessage(), e);
        }
    }

    private void parseResponse(String body) {
        if (!StringUtils.hasText(body)) {
            throw new IllegalStateException("钉钉接口返回为空");
        }
        try {
            JsonNode root = objectMapper.readTree(body);
            int errcode = root.path("errcode").asInt(-1);
            if (errcode != 0) {
                String errmsg = root.path("errmsg").asText("未知错误");
                throw new IllegalStateException("钉钉发送失败：" + errmsg + "（errcode=" + errcode + "）");
            }
        } catch (IllegalStateException e) {
            throw e;
        } catch (Exception e) {
            throw new IllegalStateException("解析钉钉响应失败：" + e.getMessage(), e);
        }
    }
}
