package com.yonge.cooleshow.common.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.base.exception.ThirdpartyException;
import com.yonge.toolset.utils.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@ControllerAdvice
public class BaseController {

    private final static Logger logger = LoggerFactory.getLogger(BaseController.class);

    public static <T> HttpResponseResult<T> succeed(T object) {
        return getResponseData(true, HttpStatus.OK, object, "");
    }

    public static <T> HttpResponseResult<T> succeed() {
        return getResponseData(true, HttpStatus.OK, null, "");
    }

    public static <T> HttpResponseResult<T> succeedData(T obj) {
        return getResponseData(true, HttpStatus.OK, obj, "操作成功");
    }

    public static <T> HttpResponseResult<T> warned(String message) {
        return failed(HttpStatus.MULTI_STATUS, message);
    }

    public static <T> HttpResponseResult<T> failed() {
        return failed("");
    }

    public static <T> HttpResponseResult<T> failed(String msg) {
        return failed(HttpStatus.INTERNAL_SERVER_ERROR, msg);
    }

    public static <T> HttpResponseResult<T> failed(HttpStatus statusCode, String msg) {
        return getResponseData(false, statusCode, null, msg);
    }

    public static <T> HttpResponseResult<T> failed(int code, String msg) {
        return getResponseData(false, code, null, msg);
    }

    public static <T> HttpResponseResult<T> status(boolean flag) {
        return flag ? succeed() : failed("操作失败");
    }

    public static <T> HttpResponseResult<T> failed(HttpStatus statusCode, T data, String msg) {
        return getResponseData(false, statusCode, data, msg);
    }

    private static <T> HttpResponseResult<T> getResponseData(boolean status, HttpStatus statusCode, T data, String message) {
        HttpResponseResult<T> obj = new HttpResponseResult<T>();
        obj.setStatus(status);
        obj.setCode(statusCode.value());
        obj.setData(data);
        obj.setMsg(message);
        return obj;
    }

    private static <T> HttpResponseResult<T> getResponseData(boolean status, int code, T data, String message) {
        HttpResponseResult<T> obj = new HttpResponseResult<T>();
        obj.setStatus(status);
        obj.setCode(code);
        obj.setData(data);
        obj.setMsg(message);
        return obj;
    }

    /**
     * 处理一般异常
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(Exception.class)
    public HttpResponseResult<String> handleException(Exception ex, HttpServletRequest request) {
        Throwable e = ExceptionUtils.getRootCause(ex);
        if (e == null) {
            e = ex;
        }
        logger.error("System Error", ex);
        if (e instanceof BizException || e instanceof ThirdpartyException) {
            if (e.getMessage().equals("205")) {
                return failed(HttpStatus.RESET_CONTENT, e.getMessage());
            }

            // 自定义错误码
            if (e instanceof BizException) {
                BizException bizException = (BizException) e;
                return getResponseData(false, bizException.getCode(), null, bizException.getMessage());
            }

            // 默认返回错误码
            return failed(e.getMessage());
        } else if (e instanceof AccessDeniedException) {
            return failed("禁止访问");
        } else if (e instanceof IllegalMonitorStateException) {
            return failed("操作失败");
        } else if (e instanceof BindException) {
            String errors = ((BindException) e).getFieldErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("\n"));
            return failed(errors);
        } else if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException validException = (MethodArgumentNotValidException) ex;
            String errorMsg = validException.getBindingResult()
                    .getFieldErrors()
                    .stream()
                    .map(FieldError::getDefaultMessage)
                    .collect(Collectors.joining());
            return failed(errorMsg);
        }
        try {

            // 机器人通知消息
            String message = getRobotRequestLog(request);

            Map<String, Object> paramMap = new HashMap<>(2);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("content", "系统繁忙请及时处理: " + message + "   " + e);
            paramMap.put("text", jsonObject.toJSONString());
            paramMap.put("msgtype", "text");
            Map<String, String> headers = new HashMap<>(1);
            headers.put("Content-Type", "application/json");
            HttpUtil.postForHttps(dingTalkRobotsSecurityParam(), JSON.toJSONString(paramMap), headers);
        } catch (Exception exception) {
            logger.error("System Error", exception);
        }
        if (StringUtils.isNotBlank(e.getMessage())) {
            return failed(e.getMessage());
        }
        return failed("系统繁忙");
    }

    /**
     * 打印异常请求日志
     * @param request HttpServletRequest
     * @return String
     */
    private String getRobotRequestLog(HttpServletRequest request){

        if (Objects.isNull(request)) {
            log.warn("getRobotRequestLog request is null");
            return "";
        }

        StringBuilder sb = new StringBuilder();
        // 打印请求日志或执行其他逻辑
        sb.append("Request URI: ").append(request.getRequestURI());

        // 请求参数
        Map<String, String> requestParams = getRequestParameters(request);
        if (!requestParams.isEmpty()) {
            sb.append(", Request Parameters: ").append(requestParams);
        }

        // 请求头
        Map<String, String> requestHeaders = getRequestHeaders(request);
        if (!requestHeaders.isEmpty()) {
            sb.append(", Request Headers: ").append(requestHeaders);
        }

        // 请求消息体
        String requestBody = getRequestBody(request);
        if (!requestBody.isEmpty()) {
            sb.append(", Request JSON: ").append(requestBody);
        }
        return sb.toString();
    }

    /**
     * 请求参数
     * @param request HttpServletRequest
     * @return Map<String, String>
     */
    private Map<String, String> getRequestParameters(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        request.getParameterMap().forEach((name, values) -> {
            if (values.length > 0) {
                params.put(name, values[0]);
            }
        });
        return params;
    }

    /**
     * 请求头
     * @param request HttpServletRequest
     * @return Map<String, String>
     */
    private Map<String, String> getRequestHeaders(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        Map<String, String> headers = new HashMap<>();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            headers.put(headerName, headerValue);
        }
        return headers;
    }

    /**
     * 请求消息体
     * @param request HttpServletRequest
     * @return String
     */
    private String getRequestBody(HttpServletRequest request) {
        StringBuilder requestBody = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                requestBody.append(line);
            }
        } catch (IOException e) {
            log.error("robot getRequestBody body: {}", e.getMessage());
        }
        return requestBody.toString();
    }

    public String dingTalkRobotsSecurityParam() throws Exception {
        Long timestamp = System.currentTimeMillis();
        String secret = "SEC7371152e58a066b358afd9e9cfaad2aee4b46471218f1aeef88d43a401d8e2f2";
        String stringToSign = timestamp + "\n" + secret;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
        byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
        String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        StringBuffer sb = new StringBuffer("https://oapi.dingtalk.com/robot/send?access_token=324dc48b8af4fc21223a5b8fd5d8daa611e106f2711d91abe1d73bce8c5c86b2&timestamp=");
        sb.append(timestamp).append("&sign=").append(sign);
        return sb.toString();
    }
}
