package com.kxs.gateway.api.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kxs.common.core.constant.CommonConstants;
import com.kxs.common.mq.handlers.IMQSender;
import com.kxs.gateway.api.config.ResponseProperties;
import com.kxs.gateway.api.rabbit.RabbitDtsMethodQueueMQ;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.reactivestreams.Publisher;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;

/**
 * 响应过滤器
 *
 * @author 没秃顶的码农
 * @date 2024-04-30
 */
@Component
@Slf4j
@EnableConfigurationProperties(ResponseProperties.class)
@RequiredArgsConstructor
public class ResponseFilter implements GlobalFilter, Ordered {

    private final ResponseProperties properties;

    private final IMQSender imqSender;

    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        if (properties.getFilterUrl().isEmpty() || !properties.getFilterUrl().contains(path)) {
            return chain.filter(exchange);
        }
        ServerHttpResponse originalResponse = exchange.getResponse();

        DataBufferFactory bufferFactory = originalResponse.bufferFactory();


        ServerHttpResponseDecorator response = new ServerHttpResponseDecorator(originalResponse) {
            @NotNull
            @Override
            public Mono<Void> writeWith(@NotNull Publisher<? extends DataBuffer> body) {
                if (Objects.equals(getStatusCode(), HttpStatus.OK) && body instanceof Flux) {
                    // 获取ContentType，判断是否返回JSON格式数据

                    String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);

                    if (StrUtil.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);

                        //（返回数据内如果字符串过大，默认会切割）解决返回体分段传输
                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                            List<String> list = new ArrayList<>();

                            dataBuffers.forEach(dataBuffer -> {
                                try {
                                    byte[] content = new byte[dataBuffer.readableByteCount()];

                                    dataBuffer.read(content);

                                    DataBufferUtils.release(dataBuffer);

                                    list.add(new String(content, StandardCharsets.UTF_8));

                                } catch (Exception e) {
                                    log.error("加载Response字节流异常，失败原因：{} ", e.getMessage(), e);
                                }

                            });

                            String responseData = String.join("", list);

                            JSONObject parse = JSON.parseObject(responseData);
                            Integer status = parse.getInteger("status");
                            if (Objects.equals(status, CommonConstants.SUCCESS)) {
                                //获取请求token
                                List<String> tokens = exchange.getRequest().getHeaders().get(HttpHeaders.AUTHORIZATION);
                                Object attribute = exchange.getAttribute("requestBody");
                                if(tokens != null && !tokens.isEmpty()){
                                    sendMsg(path, attribute, tokens.get(0));
                                }else{
                                    sendMsg(path, attribute, null);
                                }

                            }

                            byte[] uppedContent = new String(responseData.getBytes(), StandardCharsets.UTF_8).getBytes();

                            originalResponse.getHeaders().setContentLength(uppedContent.length);

                            return bufferFactory.wrap(uppedContent);

                        }));
                    }

                }
                return super.writeWith(body);
            }

            @NotNull
            @Override
            public Mono<Void> writeAndFlushWith(@NotNull Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));

            }

        };
        return chain.filter(exchange.mutate().response(response).build());

    }


    @Override
    public int getOrder() {
        return Integer.MIN_VALUE;
    }

    private void sendMsg(String url, Object param, String token) {
        Object userId = null;
        if(StrUtil.isNotBlank(token)){
            if (token.startsWith("Bearer ")) {
                token = token.substring(7);
            }
            userId = redisTemplate.opsForValue().get(token);
        }


        //发送消息
        RabbitDtsMethodQueueMQ msg = RabbitDtsMethodQueueMQ.build(RabbitDtsMethodQueueMQ.MsgEntity.builder()
                .url(url)
                .userId(userId)
                .param(param != null ? param.toString() : "")
                .build());
        imqSender.send(msg);
        log.info("send msg success, msg={}", JSON.toJSONString(msg));
    }


}