package com.fdkanfang.web.backend;

import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fdkanfang.common.constant.MsgCode;
import com.fdkanfang.common.enums.ResultCodeEnum;
import com.fdkanfang.common.exception.CommonBaseException;
import com.fdkanfang.common.sms.SmsService;
import com.fdkanfang.common.util.*;
import com.fdkanfang.domain.backend.UserEntity;
import com.fdkanfang.domain.dto.LoginDto;
import com.fdkanfang.domain.dto.RegisterDto;
import com.fdkanfang.domain.dto.UserLoginVo;
import com.fdkanfang.service.backend.ResourceService2;
import com.fdkanfang.service.backend.UserService2;
import com.fdkanfang.service.backend.dto.ResourceTree;
import com.fdkanfang.web.aop.WebControllerLog;
import com.fdkanfang.web.backend.utils.UserUtils;
import com.fdkanfang.web.shiro.JWTUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created by owen on 2020/2/19 0019 15:53
 */
//@Api(value = "IndexController",tags = "登录/退出")
@Api(value = "IndexController", tags = "登录管理")
@RestController
@Log4j2
public class IndexController extends BaseController {


    @Autowired
    private UserService2 userService2;

    @Autowired
    private ResourceService2 resourceService;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Value("${4dkankan.host}")
    private String KankanHost;

    @WebControllerLog(description = "用户管理-登录")
    @ApiOperation("登录")
    @PostMapping("admin/login")
    public R login(@RequestBody LoginDto param) throws Exception {
        // 1.获取用户
        UserEntity user = userService2.findByUserName(param.getUserName());
        if (user == null) {
            log.error("用户不存在： {}", param.getUserName());
            return new R(MsgCode.e_ADMIN_4001, MsgCode.msg_ADMIN_4001);
        }

        // 验证密码
        Boolean isBoolean = PasswordUtils.decrypt(user.getPassword(), param.getPassword(), PasswordUtils.getStaticSalt());
        if (!isBoolean) {
            log.error("验证密码错误： {}", param.getPassword());
            return new R(MsgCode.e_ADMIN_4002, MsgCode.msg_ADMIN_4002);
        }

        // 检查账号是否启用
        if (user.getStatus() != 0) {
            log.error("账户已停用，不能登录： {}", param.getUserName());
            return new R(5100, "该账户已停用，请跟管理员联系");
        }

        // 获取用户菜单
        List<ResourceTree> resourcesTreeByUserPermission = resourceService.getResourcesTreeByUserPermission(user);

        // 获取用户角色
        Set<String> roles = userService2.findRoleByUserId(user.getId());


        // 创建新token
        HashMap<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("userName", param.getUserName());
        tokenMap.put("id", user.getId());
        tokenMap.put("role", roles);

        String token = JWTUtil.sign(tokenMap, user.getPassword());

        HashMap<String, Object> result = new HashMap<>();
        result.put("user", user);
        result.put("token", token);
        result.put("permission", resourcesTreeByUserPermission);
        result.put("role", roles);


        // 更新到 redis, 有效期24h, 旧token无效
        redisTemplate.opsForValue().set(user.getUserName(), token, Long.parseLong("24"), TimeUnit.HOURS);
        return new R(MsgCode.SUCCESS_CODE, result);
    }

    @ApiOperation(value = "管理员登录")
    @PostMapping(value = "user/login")
    @ResponseBody
    public Result userLogin(@RequestBody @ApiParam(name = "用户登录注册实体", value = "传入json格式", required = true) UserLoginVo adminRegisterVo) {
        if (null == adminRegisterVo) {
            throw new CommonBaseException(ResultCodeEnum.D3001);
        }
        if (!StringUtils.isNoneBlank(adminRegisterVo.getPhoneNum(), adminRegisterVo.getPassword())) {
            throw new CommonBaseException(ResultCodeEnum.D3001);
        }
        adminRegisterVo.setRandomcode("1234");
        adminRegisterVo.setRememberMe(true);
        String url = KankanHost + "api/sso/user/login";
        String json = JsonUtils.objectToJson(adminRegisterVo);
        String kankanResult = HttpClientUtil.doPostJson(url, json);
        //解析返回结果
        JSONObject res = JSONObject.parseObject(kankanResult);
        log.info("四维看看返回登录数据:{}", res.toJSONString());

        Result result = parseResult(res, "登录失败", adminRegisterVo);
        if (result.getCode() == 0) {
            // 1.获取用户
            UserEntity user = userService2.findByPhone(adminRegisterVo.getPhoneNum());
            if (user == null) {
                log.error("用户不存在： {}", adminRegisterVo);
                throw new CommonBaseException(ResultCodeEnum.D3012);
            }
            // 检查账号是否启用
            if (user.getStatus() != 0) {
                log.error("账户已停用，不能登录： {}", adminRegisterVo.getPhoneNum());
                throw new CommonBaseException(ResultCodeEnum.D101, "账号已停用，如需使用请联系管理员");
            }
        }
        return result;
    }


    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public Result parseResult(JSONObject res, String defaultFailMsg, UserLoginVo adminRegisterVo) {
        if (null != res) {
            int code = -10;
            if (res.containsKey("code")) {
                code = (int) res.get("code");
            }
            String msg = null;
            if (res.containsKey("msg")) {
                msg = (String) res.get("msg");
            }
            Map<String, Object> resultMap = new HashMap<>();
            if (0 == code) {
                log.info("用户登录成功");
                JSONArray dataObjArray = null;
                JSONObject dataObject = null;
                String tokenFromKankan = "";
                if (res.get("data") instanceof JSONArray) {
                    log.info("四维看看登录返回的data是json数组");
                    dataObjArray = (JSONArray) res.get("data");
                    return Result.success(msg, dataObjArray);
                } else if (res.get("data") instanceof JSONObject) {
                    log.info("四维看看登录返回的data是json object");
                    //登录返回的就是jsonObject
                    dataObject = (JSONObject) res.get("data");
                    if (null != dataObject) {
                        JSONObject user = (JSONObject) dataObject.get("user");
                        tokenFromKankan = dataObject.getString("token");
                        if (StringUtils.isBlank(tokenFromKankan)) {
                            throw new CommonBaseException(ResultCodeEnum.D101, "四维看看返回的token为空");
                        }
                        resultMap.put("token", tokenFromKankan);
                        if (null == user) {
                            log.info("解析不出來user");
                            throw new CommonBaseException(ResultCodeEnum.D101, "解析看看返回的数据失败");
                        } else {
                            String nickName = (String) user.get("nickName");
                            String userName = (String) user.get("userName");
                            String password = (String) user.get("password");
                            int kankanUserId = null != user.get("id") ? (int) user.get("id") : -1;
                            if (StringUtils.isBlank(userName)) {
                                throw new CommonBaseException(ResultCodeEnum.D101, "看看返回用户名为空");
                            }
                            UserEntity dbUser = userService2.findByUserName(userName);
                            if (null == dbUser) {
                                userUtils.addNewUserByPhone(userName, password , kankanUserId);
                                dbUser = userService2.findByUserName(adminRegisterVo.getPhoneNum());
                                if (null == dbUser) {
                                    log.error("新插入的用户:{}重新捞取失败", adminRegisterVo.getPhoneNum());
                                    throw new CommonBaseException(ResultCodeEnum.D101, "获取用户失败");
                                }
                                //默认给上传权限
                                userService2.saveUserRole(dbUser.getId(), 2l);
                            } else {
                                if (!StringUtils.equals(dbUser.getRecStatus(), "A")) {
                                    log.info("用户[{}]不可用", dbUser.getUserName());
                                    throw new CommonBaseException(ResultCodeEnum.D101, "用户已经不可用");
                                }
                                if(kankanUserId != -1 && null == dbUser.getKankanUserId()){
                                    dbUser.setKankanUserId(kankanUserId);
                                    int update = userService2.update(dbUser);
                                    if(update != 1){
                                        log.warn("更新用户的看看用户ID失败");
                                    }
                                }
                                Set<String> roles = userService2.findRoleByUserId(dbUser.getId());
                                if (null == roles || !roles.contains("upload")) {
                                    //默认给上传权限
                                    userService2.saveUserRole(dbUser.getId(), 2l);
                                }
                            }
                            resultMap.put("user", dbUser);
                        }
                    }
                    return Result.success(msg, resultMap);
                } else {
                    return Result.failure("四维看看返回数据测试异常");
                }
            } else {
                return Result.failure(msg);
            }
        }
        return Result.failure(defaultFailMsg);
    }


    @ApiOperation("退出")
    @GetMapping("admin/logout")
    public R logout() {
        log.info("run logout");

        String userName = JWTUtil.getUserName(getToken());
        String redisToken = redisTemplate.opsForValue().get(userName);
        // token username 一致，代表没有被踢出
        if (userName.equals(redisToken)) {
            redisTemplate.delete(userName);
        }

        log.info("end logout");
        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }

    @ApiOperation("用户注册/重置密码")
    @PostMapping("admin/register")
    public R register(@Valid @RequestBody RegisterDto param) {
        @NotBlank(message = "手机号不能为空") String phone = param.getPhone();
        if (!Validator.isMobile(phone)) {
            log.error("手机号有误： {}", phone);
            return new R(MsgCode.e_COMMON_3003, MsgCode.msg_COMMON_3003);
        }

        // 1.检查验证码
        String code = redisTemplate.opsForValue().get(phone);
        if (StringUtils.isAllBlank(code)) {
            log.error("验证码过期");
            return new R(MsgCode.e_COMMON_3001, "验证码过期");
        }

        if (!code.equals(param.getCode())) {
            log.error("验证码不正确");
            return new R(MsgCode.e_COMMON_3001, "验证码不正确");
        }

        // 2.检查密码一致性
        if (!param.getPassword().equals(param.getConfirmPassword())) {
            log.error("密码不一致");
            return new R(MsgCode.e_COMMON_3001, "密码不一致");
        }

        // 3.保存用户
        UserEntity user = userService2.findByPhone(phone);
        // 注册用户
        if (user == null) {
            user = new UserEntity();
            // 新用户，用户名就是手机号
            user.setUserName(phone);
            user.setPhone(phone);
            user.setRealName(phone);
            // 用户名不能修改，加密需要他，改了就密码就失效
            user.setPassword(PasswordUtils.encrypt(user.getUserName(), param.getPassword(), PasswordUtils.getStaticSalt()));
            userService2.save(user);
        } else {
            // 设置&重置密码
            user.setPassword(PasswordUtils.encrypt(user.getUserName(), param.getPassword(), PasswordUtils.getStaticSalt()));
            user.setUpdateTime(new Date());
            userService2.update(user);
        }


        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);

    }

    @ApiOperation("获取验证码")
    @GetMapping("admin/getCode/{phone}")
    public R getCode(@PathVariable String phone) {

        if (!Validator.isMobile(phone)) {
            log.error("手机号有误： {}", phone);
            return new R(MsgCode.e_COMMON_3003, MsgCode.msg_COMMON_3003);
        }
        // 创建4位数的验证码
        int num = new Random().nextInt(9999);

        /**
         * 对接短信平台
         * 四维看房：SMS_184616399
         *
         */
        SmsService.sendSms(phone, "{\"code\":\"" + num + "\"}", "SMS_184616399");

        // 更新到 redis, 有效期5分钟, 旧token无效
        redisTemplate.opsForValue().set(phone, String.valueOf(num), Long.parseLong("360"), TimeUnit.SECONDS);

        return new R(MsgCode.SUCCESS_CODE, num);
    }

    @GetMapping("test")
    public String test() {
        return LocalDateTime.now().toString();
    }


    public static void main(String[] args) {
        System.out.println(Validator.isMobile("015015980188"));
    }

}