package cn.reghao.tnb.user.app.controller;

import cn.reghao.jutil.jdk.serializer.JsonConverter;
import cn.reghao.tnb.user.api.dto.UserInfo;
import cn.reghao.tnb.user.app.hystrix.SimpleHystrixCommand;
import cn.reghao.tnb.user.app.hystrix.observable.HaloSemaphoreIsolationCommand;
import cn.reghao.tnb.user.app.hystrix.observable.HaloThreadIsolationCommand;
import cn.reghao.tnb.user.app.service.UserServiceHystrix;
import cn.reghao.tnb.user.app.service.UserProfileService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import rx.Observable;

import java.util.HashMap;
import java.util.Map;

/**
 * @author reghao
 * @date 2025-07-19 23:59:57
 */
@Slf4j
@RestController
@RequestMapping("/api/user/hystrix")
@DefaultProperties(defaultFallback = "defaultFallback")
public class UserControllerHystrix {
    private final UserProfileService userProfileService;
    private final UserServiceHystrix userServiceHystrix;
    private HaloSemaphoreIsolationCommand haloSemaphoreIsolationCommand;
    private HaloThreadIsolationCommand haloThreadIsolationCommand;

    public UserControllerHystrix(UserProfileService userProfileService, UserServiceHystrix userServiceHystrix,
                                 HaloSemaphoreIsolationCommand haloSemaphoreIsolationCommand,
                                 HaloThreadIsolationCommand haloThreadIsolationCommand) {
        this.userProfileService = userProfileService;
        this.userServiceHystrix = userServiceHystrix;
        this.haloSemaphoreIsolationCommand = haloSemaphoreIsolationCommand;
        this.haloThreadIsolationCommand = haloThreadIsolationCommand;
    }

    @Operation(summary = "获取用户资料", description = "N")
    @GetMapping(value = "/info", produces = MediaType.APPLICATION_JSON_VALUE)
    public String getUserInfo(@RequestParam("userId") Long userId) {
        UserHolder.setUser("reghao");
        userServiceHystrix.hello();
        log.info("user -> {}", UserHolder.getUser());

        /*Observable<String> observable = haloThreadIsolationCommand.toObservable();
        String result = observable.toBlocking().single();*/

        /*Observable<String> observable1 = haloSemaphoreIsolationCommand.toObservable();
        String result1 = observable1.toBlocking().single();*/

        /*SimpleHystrixCommand simpleHystrixCommand = new SimpleHystrixCommand(userServiceHystrix);
        String result2 = simpleHystrixCommand.execute();*/

        //UserInfo userInfo = userProfileService.getUserInfo(userId);
        String userInfoJson = userServiceHystrix.getUserInfo(userId);
        return userInfoJson;
    }

    @GetMapping(value = "/info1", produces = MediaType.APPLICATION_JSON_VALUE)
    @HystrixCommand(
            fallbackMethod = "getUserInfoFallback",
            commandProperties = {
                    @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED, value = "false"),
                    // 5 秒内, 请求达到 4 个以上, 失败率达到 50% 以上, 则开启熔断, 此时会直接使用 fallback, 不会再调用业务方法
                    // 熔断 3 秒后有请求到来, 则会再执行一次业务方法, 执行失败则继续保持熔断, 执行成功则取消熔断
                    @HystrixProperty(name="metrics.rollingStats.timeInMilliseconds", value="5000"),
                    @HystrixProperty(name="circuitBreaker.requestVolumeThreshold", value="4"),
                    @HystrixProperty(name="circuitBreaker.errorThresholdPercentage", value="50"),
                    @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds", value="3000")
            })
    public UserInfo getUserInfo1(@RequestParam("userId") Long userId) {
        UserHolder.setUser("reghao");
        userServiceHystrix.hello();
        log.info("user -> {}", UserHolder.getUser());
        UserInfo userInfo = userServiceHystrix.getUserInfo1(userId);
        return userInfo;
    }

    public UserInfo getUserInfoFallback(Long userId) {
        System.out.printf("hystrix fallback with userId %s\n", userId);
        Map<String, String> map = new HashMap<>();
        map.put("code", "0");
        map.put("msg", "hystrix fallback");
        return null;
    }

    public String defaultFallback() {
        Map<String, String> map = new HashMap<>();
        map.put("code", "0");
        map.put("msg", "hystrix default fallback");
        return JsonConverter.objectToJson(map);
    }

    public static class UserHolder{
        private static ThreadLocal<String> userHolder = new ThreadLocal<>();

        public static void setUser(String user){
            userHolder.set(user);
        }

        public static String getUser(){
            return userHolder.get();
        }

        public static void clean(){
            userHolder.remove();
        }
    }
}
