package com.mosty.common.core.login;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.code.kaptcha.Producer;
import com.mosty.common.base.constant.Constants;
import com.mosty.common.base.domain.ResponseResult;
import com.mosty.common.base.exception.BusinessException;
import com.mosty.common.base.util.Base64Util;
import com.mosty.common.base.util.PasswordUtil;
import com.mosty.common.base.util.StringUtils;
import com.mosty.common.core.business.entity.SysDept;
import com.mosty.common.core.business.entity.SysUser;
import com.mosty.common.core.business.entity.vo.DeptQuery;
import com.mosty.common.core.business.entity.vo.SysUserVO;
import com.mosty.common.core.business.service.*;
import com.mosty.common.core.config.CaptchaConfig;
import com.mosty.common.core.login.dto.DeptAllVo;
import com.mosty.common.core.login.dto.DeptDTO;
import com.mosty.common.redis.service.RedisService;
import com.mosty.common.token.JwtSysUser;
import com.mosty.common.token.UserInfo;
import com.mosty.common.token.UserInfoManager;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static com.mosty.common.base.constant.Constants.LOGOUT;
import static com.mosty.common.base.constant.SystemConfigConstants.TOKEN_PREFIX;

/**
 * 登陆服务
 * <p>
 * jwt:
 * secret: "" # 验签的key
 * #  expiration: 432000 # 配置文件中过期时间，单位秒
 * issuer: ""
 *
 * @author kevin
 * @date 2022/2/15 8:25 PM
 * @since 1.0.0
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/")
@Api(tags = "登陆服务")
public class LoginServiceController {

    private final SysUserService sysUserService;
    private final SysDeptService sysDeptService;
    private final Producer captchaProducer;
    private final RedisService redisService;
    private final JwtTokenGenerator jwtTokenGenerator;
    private final SysUserRoleService sysUserRoleService;
    private final SysRoleService sysRoleService;
    private final SysLogininforService sysLogininforService;
    private final CaptchaConfig captchaConfig;
    private final LoginService loginService;
    private final TbJcglXfllInCommService tbJcglXfllService;

    @PostMapping("/login")
    @ApiOperation(value = "根据账号和密码登录", httpMethod = "POST", response = LoginResponseVO.class)
    public ResponseResult<LoginResponseVO> login(@Valid @RequestBody LoginRequest dto, HttpServletRequest httpServletRequest) throws Exception {
        String status = "";
        String message = "";

        SysUser sysUser;
        if(StringUtils.isBlank(dto.getType()) || "01".equals(dto.getType())){
            // 验证用户信息
            QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("xt_zxbz", "0");
//            queryWrapper.eq("id_entity_card", dto.getUserName());
//            queryWrapper.or().eq("in_dust_rial_id", dto.getUserName());
            queryWrapper.eq("mobile", dto.getUserName());
            sysUser = sysUserService.getBaseMapper().selectOne(queryWrapper);
        }else if("02".equals(dto.getType())){
            sysUser = tbJcglXfllService.selectFjToUserByLogin(dto.getUserName());
        }else{
            return ResponseResult.fail("类型不规范!");
        }

        if (sysUser == null) return ResponseResult.fail("用户名或密码错误!");
        try {
            // 验证密码
            String password = new String(Base64Util.decryptBASE64(dto.getPassword().getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
            boolean match = PasswordUtil.match(password, sysUser.getPassword());
            if (!match) return ResponseResult.fail("用户名或密码错误！");
            // 查询用户关联的部门
            List<DeptDTO> deptList = new ArrayList<>();
            if(StringUtils.isBlank(dto.getType()) || "01".equals(dto.getType())){
                deptList = sysDeptService.selectUserDeptList(sysUser.getId());
            }else if("02".equals(dto.getType())){
                DeptQuery query = new DeptQuery();
                query.setDeptId(sysUser.getManagerOrgId());
                deptList = sysDeptService.buildDtoListBySysList(sysDeptService.selectDeptForLogin(query));
            }else{
                return ResponseResult.fail("类型不规范!");
            }
            DeptDTO dept = CollectionUtils.isNotEmpty(deptList) ? deptList.get(0) : null;
            if (dept == null) throw new BusinessException("用户未绑定任何部门！");
            //创建JWTToken
            DeptAllVo allVo = this.sysDeptService.getOrgByDeptId(String.valueOf(dept.getDeptId()));
            String jwtToken = jwtTokenGenerator.generateToken(sysUser, allVo);
            LoginResponseVO loginResponseVO = new LoginResponseVO(jwtToken, sysUser.getId(),
                    sysUser.getUserName(), deptList, sysUser.getIdEntityCard()
                    , sysUser.getSfrh(), sysUser.getMk());
            this.loginService.getMenus(dept, sysUser, loginResponseVO);
            // 在数据库中排序，获取第一个作为当前登陆的用户部门
            status = Constants.LOGIN_SUCCESS;
            message = "登录成功";
            loginResponseVO.setUserName(sysUser.getUserName());
            String userFix = sysUser.getId() == null ? sysUser.getIdEntityCard() : sysUser.getId().toString();
            redisService.setCacheObject(TOKEN_PREFIX + dept.getDeptId() + ":" + userFix, System.currentTimeMillis());
            return ResponseResult.success(loginResponseVO);
        } catch (Exception e) {
            e.printStackTrace();
            status = Constants.LOGIN_FAIL;
            message = "登录失败" + e.getMessage();
            throw new Exception(e.getMessage());
        } finally {
            try {
                sysLogininforService.recordLogininfor(sysUser, status, message, httpServletRequest, "02");
            } catch (Exception e) {
                log.warn("记录日志失败，message={}", e.getMessage());
                e.printStackTrace();
            }
        }
    }


    @PostMapping("/loginOauth")
    @ApiOperation(value = "根据账号和密码登录(无需权限信息和token)", httpMethod = "POST", response = SysUserVO.class)
    public ResponseResult<LoginResponseVO> loginOauth(@Valid @RequestBody LoginEntity loginEntity, HttpServletRequest request) throws Exception {
        String status = "", message = "";
        // 验证用户信息
        SysUserVO userVO = new SysUserVO();
        SysUser sysUser = sysUserService.getBaseMapper().selectOne(
                new LambdaQueryWrapper<SysUser>()
                        .eq(SysUser::getXtZxbz, "0")
                        .and(
                                it -> it.eq(SysUser::getInDustRialId, loginEntity.getUserName())
                                        .or()
                                        .eq(SysUser::getIdEntityCard, loginEntity.getUserName())
                        )
                        .last(" limit 1")
        );
        if (sysUser == null) return ResponseResult.fail("用户名或密码错误");

        try {
            // 验证密码
            String password = new String(Base64Util.decryptBASE64(loginEntity.getPassword().getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
            boolean match = PasswordUtil.match(password, sysUser.getPassword());
            if (!match) return ResponseResult.fail("用户名或密码错误！");
            // 查询用户关联的部门
            List<DeptDTO> deptList = sysDeptService.selectUserDeptList(sysUser.getId());
            DeptDTO dept = CollectionUtils.isNotEmpty(deptList) ? deptList.get(0) : null;
            if (dept == null) throw new BusinessException("用户未绑定任何部门！");
            //创建JWTToken
            DeptAllVo allVo = this.sysDeptService.getOrgByDeptId(String.valueOf(dept.getDeptId()));
            String jwtToken = jwtTokenGenerator.generateToken(sysUser, allVo);
            LoginResponseVO loginResponseVO = new LoginResponseVO(jwtToken, sysUser.getId(),
                    sysUser.getUserName(), deptList, sysUser.getIdEntityCard(), sysUser.getSfrh(), sysUser.getMk());
            this.loginService.getMenus(dept, sysUser, loginResponseVO);
            // 在数据库中排序，获取第一个作为当前登陆的用户部门
            status = Constants.LOGIN_SUCCESS;
            message = "登录成功";
            loginResponseVO.setUserName(sysUser.getUserName());
            redisService.setCacheObject(TOKEN_PREFIX + dept.getDeptId() + ":" + sysUser.getId(), System.currentTimeMillis());
            return ResponseResult.success(loginResponseVO);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            status = Constants.LOGIN_FAIL;
            message = "登录失败" + e.getMessage();
            throw new Exception(e.getMessage());
        } finally {
            try {
                sysLogininforService.recordLogininfor(sysUser, status, message, request, "02");
            } catch (Exception e) {
                log.warn("记录日志失败，message={}", e.getMessage());
                e.printStackTrace();
            }
        }
    }

    // 根据当前部门获取分县局部门
    public SysDept getFxjDept(DeptDTO currentDept) {
        if (currentDept == null) {
            return null;
        }
        Long id = null;
        String path = currentDept.getPath();
        if (path.contains("_")) {
            String[] paths = path.split("_");
            log.info("paths length--->" + paths.length);
            if (paths.length == 2) {
                id = Long.valueOf(paths[1]);
            } else if (paths.length == 3) {
                id = Long.valueOf(paths[2]);
            } else if (paths.length >= 4) {
                id = Long.valueOf(paths[2]);
            }
        } else {
            id = Long.valueOf(path);
        }
        return sysDeptService.getById(id);
    }

    // 根据当前地市州
    public SysDept getDszDept(DeptDTO currentDept) {
        if (currentDept == null) return null;
        long id;
        String path = currentDept.getPath();
        if (path.contains("_")) {
            String[] paths = path.split("_");
            id = Long.parseLong(paths[1]);
        } else {
            id = Long.parseLong(path);
        }
        return sysDeptService.getById(id);
    }

    @PostMapping("/idCardNoLogin")
    @ApiOperation(value = "APP--身份证号登陆", httpMethod = "POST", response = LoginResponseVO.class)
    public ResponseResult<LoginResponseVO> idCardNoLogin(@Valid @RequestBody IdCardLoginRequest idCardLoginRequest,
                                                         HttpServletRequest httpServletRequest) throws Exception {
        String status = "";
        String message = "";
        SysUser sysUser = null;
        try {
            // 验证用户信息
            QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id_entity_card", idCardLoginRequest.getIdCardNo());
            sysUser = sysUserService.getBaseMapper().selectOne(queryWrapper);
            if (sysUser == null) return ResponseResult.fail("用户不存在！！");

            // 查询用户关联的部门
            List<DeptDTO> deptList = sysDeptService.selectUserDeptList(sysUser.getId());
            DeptDTO dept = CollectionUtils.isNotEmpty(deptList) ? deptList.get(0) : null;
            //除非用户是超级管理员，否则部门为空不允许登陆
            if (dept == null) return ResponseResult.fail("用户未分配任何部门！！");
            //创建JWTToken
            DeptAllVo allVo = this.sysDeptService.getOrgByDeptId(String.valueOf(dept.getDeptId()));
            String jwtToken = jwtTokenGenerator.generateToken(sysUser, allVo);
            LoginResponseVO loginResponseVO = new LoginResponseVO(jwtToken, sysUser.getId(), sysUser.getUserName(), deptList,
                    sysUser.getIdEntityCard(), sysUser.getSfrh(), sysUser.getMk());
            // 在数据库中排序，获取第一个作为当前登陆的用户部门
            status = Constants.LOGIN_SUCCESS;
            message = "登录成功";
            redisService.setCacheObject(TOKEN_PREFIX + dept.getDeptId() + ":" + sysUser.getId(), System.currentTimeMillis());
            return ResponseResult.success(loginResponseVO);
        } catch (Exception e) {
            e.printStackTrace();
            status = Constants.LOGIN_FAIL;
            message = "登录失败" + e.getMessage();
            throw new Exception(e.getMessage());
        } finally {
            if (sysUser != null) {
                try {
                    sysLogininforService.recordLogininfor(sysUser, status, message, httpServletRequest, "01");
                } catch (Exception e) {
                    log.warn("记录日志失败，message={}", e.getMessage());
                }
            }
        }
    }

    @PostMapping("/ssoLogin")
    @ApiOperation(value = "APP--身份证号登陆", httpMethod = "POST", response = LoginResponseVO.class)
    public ResponseResult<LoginResponseVO> ssoLogin(@RequestBody LoginEntity loginEntity,
                                                    HttpServletRequest httpServletRequest) throws Exception {
        if (StringUtils.isBlank(loginEntity.getToken())) {
            return ResponseResult.fail("用户名不能为空");
        }
        String status = "", message = "", userName;
        SysUser sysUser = null;
        userName = new String(Base64Util.decryptBASE64(loginEntity.getToken().getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);

        try {
            // 验证用户信息
            QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id_entity_card", userName);
            sysUser = sysUserService.getBaseMapper().selectOne(queryWrapper);
            if (sysUser == null) return ResponseResult.fail("用户不存在！！");
            // 查询用户关联的部门
            List<DeptDTO> deptList = sysDeptService.selectUserDeptList(sysUser.getId());
            DeptDTO dept = CollectionUtils.isNotEmpty(deptList) ? deptList.get(0) : null;
            if (dept == null) throw new BusinessException("用户未绑定任何部门！");
            //创建JWTToken
            DeptAllVo allVo = this.sysDeptService.getOrgByDeptId(String.valueOf(dept.getDeptId()));
            String jwtToken = jwtTokenGenerator.generateToken(sysUser, allVo);
            LoginResponseVO loginResponseVO = new LoginResponseVO(jwtToken, sysUser.getId(),
                    sysUser.getUserName(), deptList, sysUser.getIdEntityCard(), sysUser.getSfrh(), sysUser.getMk());
            this.loginService.getMenus(dept, sysUser, loginResponseVO);
            // 在数据库中排序，获取第一个作为当前登陆的用户部门
            status = Constants.LOGIN_SUCCESS;
            message = "登录成功";
            loginResponseVO.setUserName(sysUser.getUserName());
            redisService.setCacheObject(TOKEN_PREFIX + dept.getDeptId() + ":" + sysUser.getId(), System.currentTimeMillis());
            return ResponseResult.success(loginResponseVO);
        } catch (Exception e) {
            e.printStackTrace();
            status = Constants.LOGIN_FAIL;
            message = "登录失败" + e.getMessage();
            throw new Exception(e.getMessage());
        } finally {
            if (sysUser != null) {
                try {
                    sysLogininforService.recordLogininfor(sysUser, status, message, httpServletRequest, "01");
                } catch (Exception e) {
                    log.warn("记录日志失败，message={}", e.getMessage());
                }
            }
        }
    }


    @JwtSysUser
    @PostMapping("/loginOut")
    @ApiOperation(value = "登出", httpMethod = "POST", response = LoginResponseVO.class)
    public ResponseResult<Boolean> loginOut(HttpServletRequest httpServletRequest) throws Exception {
        try {
            UserInfo userInfo = UserInfoManager.getUser();
            if (userInfo != null) {
                SysUser sysUser;
                if(userInfo.getUserId() != null){
                    //民警
                    sysUser = sysUserService.getUserInfo(userInfo.getUserId());
                }else{
                    //辅警
                    sysUser = tbJcglXfllService.selectFjToUserByLogin(userInfo.getIdEntityCard());
                }
                // 查询用户关联的部门
                SysDept sysDept = sysDeptService.getById(userInfo.getDeptId());
                DeptAllVo allVo = this.sysDeptService.getOrgByDeptId(String.valueOf(sysDept.getId()));
                // 在数据库中排序，获取第一个作为当前登陆的用户部门
                jwtTokenGenerator.removeToken(sysUser, allVo);
                //清除用户jwtToken
                String userFix = sysUser.getId() == null ? sysUser.getIdEntityCard() : sysUser.getId().toString();
                redisService.deleteObject(TOKEN_PREFIX + userInfo.getDeptId() + ":" + userFix);
                sysLogininforService.recordLogininfor(sysUser, LOGOUT, "用户登出", httpServletRequest, "02");
            }
            return ResponseResult.success(Boolean.TRUE);
        } catch (Exception e) {
            log.error("登出错误：", e);
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }
    }

}
