package com.qiuguo.iot.user.api.controller.user;

import com.alibaba.fastjson.JSONObject;
import com.qiuguo.iot.base.constans.RedisConstans;
import com.qiuguo.iot.base.constans.UserAuthContains;
import java.time.Duration;
import java.util.Objects;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;

/**
 * XXX
 *
 * @author weiyachao
 * @since 2023/8/3 17:29
 */

@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {
    private final WebClient webClient = WebClient.builder()
            .defaultHeader(HttpHeaders.CONTENT_TYPE,APPLICATION_FORM_URLENCODED_VALUE)
            .defaultHeader("Api-Type","iot")
            .build();
    
    @Value("${userUrl.baseUrl}")
    private String baseUrl;
    
    @Value("${userUrl.pwdUrl}")
    private String pwdUrl;
    
    @Value("${userUrl.smsUrl}")
    private String smsUrl;
    
    @Value("${userUrl.sendSmsUrl}")
    private String sendSmsUrl;
    
    @Value("${userUrl.registerUrl}")
    private String registerUrl;
    
    @Value("${userUrl.changeUrl}")
    private String changeUrl;
    
    @Value("${userUrl.userCancelUrl}")
    private String userCancelUrl;
    
    @Value("${userUrl.userInfoUrl}")
    private String userInfoUrl;
    
    @Value("${userUrl.firstPasswordUrl}")
    private String firstPasswordUrl;
    
    @Value("${userUrl.editUserInfoUrl}")
    private String editUserInfoUrl;
    
    @Resource
    private ReactiveStringRedisTemplate reactiveStringRedisTemplate;
    
    /**
     * 修改登录密码-auth
     */
    @PostMapping("/change")
    public Mono<JSONObject> change(@RequestBody JSONObject jsonObject, @RequestHeader(UserAuthContains.API_TOKEN) String token,
            @RequestHeader(UserAuthContains.API_TYPE) String type) {
        WebClient authWebClient = getAuthWebClient(token, type);
        return authWebClient.post().uri(baseUrl + changeUrl).bodyValue(getMultiValueMap(jsonObject)).retrieve()
                .bodyToMono(JSONObject.class).doOnNext(res -> {
                    if (!Objects.equals(res.getInteger("code"), 1)) {
                        throw new RuntimeException(res.getString("info"));
                    }
                });
    }
    
    /**
     * 账号注销-auth
     */
    @PostMapping("/userCance")
    public Mono<JSONObject> userCance(@RequestBody JSONObject jsonObject, @RequestHeader(UserAuthContains.API_TOKEN) String token,
            @RequestHeader(UserAuthContains.API_TYPE) String type) {
        return getAuthWebClient(token, type).post().uri(baseUrl + userCancelUrl)
                .bodyValue(getMultiValueMap(jsonObject))
                .retrieve()
                .bodyToMono(JSONObject.class).doOnNext(res -> {
                    if (!Objects.equals(res.getInteger("code"), 1)) {
                        throw new RuntimeException(res.getString("info"));
                    }
                });
    }
    
    /**
     * 修改用户信息-auth
     */
    @PostMapping("/edit/userInfo")
    public Mono<JSONObject> editUserInfo(@RequestBody JSONObject jsonObject, @RequestHeader(UserAuthContains.API_TOKEN) String token,
            @RequestHeader(UserAuthContains.API_TYPE) String type) {
        return webClient.mutate()
                .defaultHeader("Api-Token", token)
                .defaultHeader("Api-Type", type).build().post().uri(editUserInfoUrl)
                .bodyValue(jsonObject)
                .retrieve()
                .bodyToMono(JSONObject.class).doOnNext(res -> {
                    if (!Objects.equals(res.getInteger("code"), 200)) {
                        throw new RuntimeException(res.getString("msg"));
                    }
                });
    }
    
    /**
     * 个人信息管理-auth
     */
    @GetMapping("/userInfo")
    public Mono<JSONObject> getUserInfo(@RequestHeader(UserAuthContains.API_TOKEN) String token,
            @RequestHeader(UserAuthContains.API_TYPE) String type) {
        return getAuthWebClient(token, type).get().uri(userInfoUrl).retrieve()
                .bodyToMono(JSONObject.class).doOnNext(res -> {
                    if (!Objects.equals(res.getInteger("code"), 200)) {
                        throw new RuntimeException(res.getString("msg"));
                    }
                });
    }
    
    /**
     * 是否设置登录密码-auth
     */
    @GetMapping("/first/password")
    public Mono<JSONObject> firstPassword(@RequestHeader(UserAuthContains.API_TOKEN) String token,
            @RequestHeader(UserAuthContains.API_TYPE) String type) {
        return getAuthWebClient(token, type).get().uri(firstPasswordUrl).retrieve()
                .bodyToMono(JSONObject.class).doOnNext(res -> {
                    if (!Objects.equals(res.getInteger("code"), 200)) {
                        throw new RuntimeException(res.getString("msg"));
                    }
                });
    }
    
    
    /**
     * 发送验证码
     */
    @PostMapping("/sendSms")
    public Mono<JSONObject> sendSms(@RequestBody JSONObject jsonObject) {
        return webClient.post().uri(baseUrl + sendSmsUrl).bodyValue(getMultiValueMap(jsonObject)).retrieve()
                .bodyToMono(JSONObject.class)
                .doOnNext(res->{
                    if (!Objects.equals(res.getInteger("code"), 1)) {
                        throw new RuntimeException(res.getString("info"));
                    }
                });
    }
    
    /**
     * 验证码登录
     */
    @PostMapping("/login/phone")
    public Mono<JSONObject> loginPhone(@RequestBody JSONObject jsonObject) {
        //登录
        return webClient.post().uri(baseUrl + smsUrl).bodyValue(getMultiValueMap(jsonObject))
                .retrieve().bodyToMono(JSONObject.class).flatMap(res -> {
                    if (Objects.equals(res.getInteger("code"), 1) && !res.getString("info")
                            .contains("该手机号还没有注册哦")) {
                        String token = res.getJSONObject("data").getJSONObject("token").getString("token");
                        return reactiveStringRedisTemplate.opsForValue()
                                .set(RedisConstans.IOT_TOKEN.concat(token), token, Duration.ofDays(7)).then(Mono.just(res));
                    } else if(!res.getString("info").contains("该手机号还没有注册哦")){
                        return Mono.error(new RuntimeException(res.getString("info")));
                    }else {
                        // 注册
                        MultiValueMap<String, String> register = new LinkedMultiValueMap<>();
                        register.add("phone", jsonObject.getString("phone"));
                        register.add("password", "null1null2null3");
                        register.add("true_password", "null1null2null3");
                        register.add("verify", jsonObject.getString("verify"));
                        register.add("pay_password", null);
                        return webClient.post().uri(baseUrl + registerUrl).bodyValue(register).retrieve()
                                .bodyToMono(JSONObject.class).flatMap(registerRes -> {
                                    if (!Objects.equals(registerRes.getInteger("code"), 1)) {
                                        return Mono.error(new RuntimeException(registerRes.getString("info")));
                                    } else {
                                        MultiValueMap<String, String> object = new LinkedMultiValueMap<>();
                                        object.add("phone", jsonObject.getString("phone"));
                                        object.add("verify", jsonObject.getString("verify"));
                                        return webClient.post().uri(baseUrl + smsUrl).bodyValue(object).retrieve()
                                                .bodyToMono(JSONObject.class).flatMap(twoRes -> {
                                                    if (!Objects.equals(twoRes.getInteger("code"), 1)) {
                                                        return Mono.error(new RuntimeException(twoRes.getString("info")));
                                                    }
                                                    String token = res.getJSONObject("data").getJSONObject("token").getString("token");
                                                    return reactiveStringRedisTemplate.opsForValue()
                                                            .set(RedisConstans.IOT_TOKEN.concat(token), token, Duration.ofDays(7)).then(Mono.just(res));
                                                    
                                                });
                                    }
                                });
                    }
                });
    }
    
    /**
     * 密码登录
     */
    @PostMapping("/login/pwd")
    public Mono<JSONObject> loginByPwd(@RequestBody JSONObject jsonObject) {
        log.info("UserController[]loginByPwd[]jsonObject:{}", jsonObject);
        return webClient.post().uri(baseUrl + pwdUrl).bodyValue(getMultiValueMap(jsonObject)).retrieve()
                .bodyToMono(JSONObject.class)
                .flatMap(res -> {
                    if (!Objects.equals(res.getInteger("code"), 1)) {
                        return Mono.error(new RuntimeException(res.getString("info")));
                    }
                    String token = res.getJSONObject("data").getJSONObject("token").getString("token");
                    return reactiveStringRedisTemplate.opsForValue()
                            .set(RedisConstans.IOT_TOKEN.concat(token), token, Duration.ofDays(7)).then(Mono.just(res));
                });
        
    }
    
    private MultiValueMap<String,String> getMultiValueMap(JSONObject jsonObject) {
        MultiValueMap<String,String> object = new LinkedMultiValueMap<>();
        jsonObject.forEach((k,v)->{
            object.add(k, String.valueOf(v));
        });
        return object;
    }
    
    private WebClient getAuthWebClient(String token, String type) {
        return webClient.mutate()
                .defaultHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_FORM_URLENCODED_VALUE)
                .defaultHeader("Api-Token", token)
                .defaultHeader("Api-Type", type).build();
    }
}
