package com.qmth.paper.library.api;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qmth.boot.api.annotation.Aac;
import com.qmth.boot.api.constant.ApiConstant;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.paper.library.business.bean.params.LoginParam;
import com.qmth.paper.library.business.bean.result.EditResult;
import com.qmth.paper.library.business.enums.LoginTypeEnum;
import com.qmth.paper.library.business.service.PaperLibraryCommonService;
import com.qmth.paper.library.common.bean.auth.AuthBean;
import com.qmth.paper.library.common.bean.result.LoginResult;
import com.qmth.paper.library.common.bean.result.UserLoginCheckResult;
import com.qmth.paper.library.common.config.DictionaryConfig;
import com.qmth.paper.library.common.contant.ApiPrefixConstant;
import com.qmth.paper.library.common.contant.SystemConstant;
import com.qmth.paper.library.common.entity.BasicAttachment;
import com.qmth.paper.library.common.entity.BasicSchool;
import com.qmth.paper.library.common.entity.SysRole;
import com.qmth.paper.library.common.entity.SysUser;
import com.qmth.paper.library.common.enums.AppSourceEnum;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import com.qmth.paper.library.common.enums.RoleTypeEnum;
import com.qmth.paper.library.common.enums.UploadFileEnum;
import com.qmth.paper.library.common.service.*;
import com.qmth.paper.library.common.util.Base64Util;
import com.qmth.paper.library.common.util.Result;
import com.qmth.paper.library.common.util.ResultUtil;
import com.qmth.paper.library.common.util.ServletUtil;
import io.swagger.annotations.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Date: 2021/3/30.
 */
@Api(tags = "系统Controller")
@RestController
@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + ApiPrefixConstant.PREFIX_COMMON)
public class SysController {
    private final static Logger log = LoggerFactory.getLogger(SysController.class);

    @Resource
    private BasicSchoolService basicSchoolService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private BasicVerifyCodeService basicVerifyCodeService;
    @Resource
    private DictionaryConfig dictionaryConfig;
    @Resource
    private PaperLibraryCommonService paperLibraryCommonService;
    @Resource
    private BasicAttachmentService basicAttachmentService;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private LibraryCommonService libraryCommonService;
    @Resource
    private AuthInfoService authInfoService;

    /**
     * 登录
     *
     * @param login
     * @return
     */
    @ApiOperation(value = "登录")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "用户信息", response = LoginResult.class)})
    @Aac(auth = false)
    public Result login(@ApiParam(value = "用户信息", required = true) @Valid @RequestBody LoginParam login, BindingResult bindingResult) throws NoSuchAlgorithmException {
        if (bindingResult.hasErrors()) {
            return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
        }
        if (Objects.nonNull(login.getSchoolCode()) && login.getSchoolCode().contains("#")) {
            login.setSchoolCode(login.getSchoolCode().substring(0, login.getSchoolCode().indexOf("#")));
        }

        BasicSchool basicSchool = null;
        if (!login.getSchoolCode().equalsIgnoreCase(SystemConstant.ADMIN_CODE)) {
            basicSchool = basicSchoolService.getBySchoolCode(login.getSchoolCode());
            if (Objects.isNull(basicSchool)) {
                throw ExceptionResultEnum.SCHOOL_NO_DATA.exception();
            }
            if (Objects.nonNull(basicSchool.getEnable()) && !basicSchool.getEnable()) {
                throw ExceptionResultEnum.SCHOOL_ENABLE.exception();
            }
        }
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        if (Objects.nonNull(basicSchool)) {
            wrapper.lambda().eq(SysUser::getSchoolId, basicSchool.getId());
        }
        // 账号密码登录
        List<SysUser> userList = null;
        if (LoginTypeEnum.ACCOUNT.name().equals(login.getType())) {
            String loginName = login.getLoginName();
            String password = login.getPassword();
            // 非空校验
            if (StringUtils.isAnyBlank(loginName, password)) {
                throw ExceptionResultEnum.USER_NO_DATA.exception();
            }
            wrapper.lambda().eq(SysUser::getLoginName, loginName);
            userList = sysUserService.list(wrapper);

            //用户不存在
            if (CollectionUtils.isEmpty(userList)) {
                throw ExceptionResultEnum.USER_NO_DATA.exception();
            }
            if (userList.size() > 1) {
                throw ExceptionResultEnum.USER_TWO_ERROR.exception();
            }

            SysUser sysUser = userList.get(0);
            if (!sysUser.getEnable()) {
                throw ExceptionResultEnum.USER_ENABLE.exception();
            }
            if (!password.equals(userList.get(0).getPassword())) {
                throw ExceptionResultEnum.USER_NO_DATA.exception();
            }
        } else if (LoginTypeEnum.PHONE.name().equals(login.getType())) {
            String mobileNumber = login.getMobileNumber();
            String code = login.getCode();
            // 非空校验
            if (StringUtils.isBlank(mobileNumber)) {
                throw ExceptionResultEnum.ERROR.exception("手机号不能为空");
            }
            if (StringUtils.isBlank(code)) {
                throw ExceptionResultEnum.ERROR.exception("验证码不能为空");
            }
            wrapper.lambda().eq(SysUser::getMobileNumber, mobileNumber);
            userList = sysUserService.list(wrapper);

            //用户不存在
            if (CollectionUtils.isEmpty(userList)) {
                throw ExceptionResultEnum.USER_NO_DATA.exception();
            }
            if (userList.size() > 1) {
                throw ExceptionResultEnum.USER_TWO_ERROR.exception();
            }
            SysUser sysUser = userList.get(0);
            // 校验验证码
            sysUserService.checkSmsCode(sysUser.getId(), sysUser.getMobileNumber(), code);

            // 如果不是共用验证码再过期
            if (!dictionaryConfig.smsDomain().getSmsNormalCode().equals(login.getCode())) {
                sysUserService.expiredVerifyCode(sysUser.getId(), sysUser.getMobileNumber());
            }
        } else {
            throw ExceptionResultEnum.ERROR.exception("登录参数错误");
        }

        if (login.getSchoolCode().equalsIgnoreCase(SystemConstant.ADMIN_CODE)) {
            userList.forEach(o -> {
                AuthBean authBean = libraryCommonService.getUserAuth(o.getId());
                if (Objects.nonNull(authBean) && Objects.nonNull(authBean.getRoleList()) && authBean.getRoleList().size() > 0) {
                    if (Objects.nonNull(authBean.getSchool())) {
                        throw ExceptionResultEnum.ERROR.exception("用户无法通过当前页面登录");
                    }
                }
            });
        }
        SysUser sysUser = userList.get(0);
        LoginResult loginResult = libraryCommonService.login(login.getPassword(), sysUser, AppSourceEnum.PAPER_LIBRARY);

        return ResultUtil.ok(loginResult);
    }

    /**
     * 登出
     *
     * @return
     */
    @ApiOperation(value = "登出")
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
    public Result logout() throws NoSuchAlgorithmException {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        libraryCommonService.removeUserInfo(sysUser.getId(), false);
        return ResultUtil.ok();
    }

    /**
     * 发送验证码
     *
     * @param loginParam
     * @return
     */
    @ApiOperation(value = "发送验证码")
    @RequestMapping(value = "/get_verify_code", method = RequestMethod.POST)
    @Aac(auth = false)
    public Result getVerifyCode(@RequestBody LoginParam loginParam) {
        String mobileNumber = loginParam.getMobileNumber();
        if (StringUtils.isBlank(mobileNumber)) {
            throw ExceptionResultEnum.ERROR.exception("手机号不能为空");
        }
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(loginParam.getSchoolCode())) {
            BasicSchool basicSchool = basicSchoolService.getBySchoolCode(loginParam.getSchoolCode());
            if (Objects.nonNull(basicSchool)) {
                wrapper.lambda().eq(SysUser::getSchoolId, basicSchool.getId());
            }
        }
        wrapper.lambda().eq(SysUser::getMobileNumber, mobileNumber);
        List<SysUser> userList = sysUserService.list(wrapper);

        //用户不存在
        if (userList == null || userList.isEmpty()) {
            throw ExceptionResultEnum.ERROR.exception("手机号不存在");
        }
        if (userList.size() > 1) {
            throw ExceptionResultEnum.ERROR.exception("手机号绑定了多个用户");
        }
        SysUser sysUser = userList.get(0);

        if (!sysUser.getEnable()) {
            throw ExceptionResultEnum.ERROR.exception("手机号被禁用");
        }

        if (SystemConstant.strNotNull(mobileNumber)) {
            basicVerifyCodeService.sendVeirfyCode(mobileNumber, sysUser);
        }
        int pwdCount = sysUser.getPwdCount();
        List<SysRole> sysRoleList = sysUserRoleService.listRoleByUserId(sysUser.getId());
        if (sysRoleList.stream().map(SysRole::getType).collect(Collectors.toSet()).contains(RoleTypeEnum.ADMIN)) {
            mobileNumber = sysUser.getLoginName() + "（特权用户）";
            pwdCount = 1;
        }
        UserLoginCheckResult userLoginCheckResult = new UserLoginCheckResult(sysUser.getId(), mobileNumber, pwdCount);
        return ResultUtil.ok(userLoginCheckResult, "");
    }


    /**
     * 发送验证码（绑定手机号）
     *
     * @param loginParam
     * @return
     */
    @ApiOperation(value = "发送验证码（绑定手机号）")
    @RequestMapping(value = "/get_verify_code_for_bind", method = RequestMethod.POST)
    @Aac(auth = false)
    public Result getVerifyCodeForBind(@RequestBody LoginParam loginParam) {
        String loginName = loginParam.getLoginName();
        String password = loginParam.getPassword();
        String schoolCode = loginParam.getSchoolCode();
        String mobileNumber = loginParam.getMobileNumber();

        if (StringUtils.isBlank(schoolCode)) {
            throw ExceptionResultEnum.ERROR.exception("学校代码不能为空");
        }
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        BasicSchool basicSchool = basicSchoolService.getBySchoolCode(loginParam.getSchoolCode());
        if (Objects.isNull(basicSchool)) {
            throw ExceptionResultEnum.ERROR.exception("学校不存在");
        }

        if (StringUtils.isBlank(mobileNumber)) {
            throw ExceptionResultEnum.ERROR.exception("手机号不能为空");
        }

        wrapper.lambda().eq(SysUser::getSchoolId, basicSchool.getId())
                .eq(SysUser::getMobileNumber, mobileNumber);
        List<SysUser> userList = sysUserService.list(wrapper);

        if (userList != null && userList.size() > 0) {
            throw ExceptionResultEnum.ERROR.exception("手机号已使用");
        }

        // 根据账号/密码取用户ID
        if (StringUtils.isBlank(loginName)) {
            throw ExceptionResultEnum.ERROR.exception("账号不能为空");
        }
        if (StringUtils.isBlank(password)) {
            throw ExceptionResultEnum.ERROR.exception("密码不能为空");
        }
        QueryWrapper<SysUser> sysUserQueryWrapper = new QueryWrapper<>();
        sysUserQueryWrapper.lambda().eq(SysUser::getSchoolId, basicSchool.getId())
                .eq(SysUser::getLoginName, loginName)
                .eq(SysUser::getPassword, password);
        SysUser sysUser = sysUserService.getOne(sysUserQueryWrapper);
        if (sysUser == null) {
            throw ExceptionResultEnum.ERROR.exception("用户数据异常");
        }

        // 发送短信验证码
        basicVerifyCodeService.sendVeirfyCode(mobileNumber, sysUser);

        int pwdCount = sysUser.getPwdCount();
        List<SysRole> sysRoleList = sysUserRoleService.listRoleByUserId(sysUser.getId());
        if (sysRoleList.stream().map(SysRole::getType).collect(Collectors.toSet()).contains(RoleTypeEnum.ADMIN)) {
            mobileNumber = sysUser.getLoginName() + "（特权用户）";
            pwdCount = 1;
        }
        UserLoginCheckResult userLoginCheckResult = new UserLoginCheckResult(sysUser.getId(), mobileNumber, pwdCount);
        return ResultUtil.ok(userLoginCheckResult, "");
    }

    @ApiOperation(value = "根据机构代码查询机构信息接口")
    @RequestMapping(value = "/school/query_by_school_code", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "学校信息", response = EditResult.class)})
    @Aac(auth = false)
    public Result queryBySchoolCode(@ApiParam(value = "机构code") @RequestParam(required = false) String code) {
        if (StringUtils.isBlank(code)) {
            throw ExceptionResultEnum.SCHOOL_NO_DATA.exception();
        }
        if (Objects.nonNull(code) && code.contains("#")) {
            code = code.substring(0, code.indexOf("#"));
        }
        if (!code.equalsIgnoreCase(SystemConstant.ADMIN_CODE)) {
            BasicSchool basicSchool = basicSchoolService.getBySchoolCode(code);
            Optional.ofNullable(basicSchool).orElseThrow(() -> ExceptionResultEnum.SCHOOL_NO_DATA.exception());
            authInfoService.appHasExpired(code);
            Map<String, String> map = new HashMap<>();
            if (Objects.nonNull(basicSchool.getLogo()) && (!basicSchool.getLogo().startsWith("http") || !basicSchool.getLogo().startsWith("https"))) {
//                String hostUrl = SystemConstant.getLocalFileHost(dictionaryConfig.fssDomain().getServer());
//                String filePath = SystemConstant.getLocalFilePath(hostUrl, basicSchool.getLogo());
//                String url = null;
//                if (filePath.startsWith("/")) {
//                    url = hostUrl + filePath;
//                } else {
//                    url = hostUrl + File.separator + filePath;
//                }
                map.put(SystemConstant.LOGO, Base64Util.stringToBase64(basicSchool.getLogo()));
            } else {
                map.put(SystemConstant.LOGO, basicSchool.getLogo());
            }
            map.put("name", basicSchool.getName());
            return ResultUtil.ok(map);
        } else {
            Map<String, String> map = new HashMap<>();
//            String path = this.getClass().getClassLoader().getResource("static/wx_logo.png").getPath();
//            if (StringUtils.isBlank(path)) {
//                map.put(SystemConstant.LOGO, Base64Util.imageToBase64(path));
//            }
            map.put("name", null);
            return ResultUtil.ok(map);
        }
    }

    @ApiOperation(value = "文件上传接口")
    @RequestMapping(value = "/file/upload", method = RequestMethod.POST)
    @Transactional
    @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
    public Result fileUpload(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file,
                             @ApiParam(value = "上传文件类型", required = true) @RequestParam UploadFileEnum type) {
        BasicAttachment basicAttachment = null;
        try {
            basicAttachment = paperLibraryCommonService.saveAttachment(file, ServletUtil.getRequestMd5(), type);
            if (Objects.isNull(basicAttachment)) {
                throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(basicAttachment)) {
                basicAttachmentService.deleteAttachment(basicAttachment);
            }
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return ResultUtil.ok(new EditResult(basicAttachment.getId(), libraryCommonService.filePreview(basicAttachment.getPath()), basicAttachment.getPages()));
    }


    @ApiOperation(value = "文件预览接口")
    @RequestMapping(value = "/file/preview", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
    public Result filePreview(@ApiParam(value = "附件id", required = false, defaultValue = "") @RequestParam(value = "id", required = false, defaultValue = "") String id) {
        if (StringUtils.isBlank(id)) {
            throw ExceptionResultEnum.ERROR.exception("没有附件");
        } else {
            BasicAttachment basicAttachment = basicAttachmentService.getById(Long.parseLong(id));
            return ResultUtil.ok(new EditResult(libraryCommonService.filePreview(basicAttachment.getPath())));
        }
    }

    @ApiOperation(value = "查询用户权限")
    @RequestMapping(value = "/get_menu", method = RequestMethod.POST)
    public Result getMenu() {
        return ResultUtil.ok(sysUserRoleService.listByUserId());
    }

    @ApiOperation(value = "获取服务器时间")
    @RequestMapping(value = "/get_system_time", method = RequestMethod.POST)
    public Result getSystemTime() {
        return ResultUtil.ok(System.currentTimeMillis());
    }

    @ApiOperation(value = "刷新缓存")
    @RequestMapping(value = "/flush_cache", method = RequestMethod.POST)
    public Result flushCache(String type) {
        libraryCommonService.flushCache(type);
        return ResultUtil.ok(true);
    }
}
