package com.zhiqiyun.open.mvc.manager.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhiqiyun.open.annotation.Permission;
import com.zhiqiyun.open.core.enmus.AccountType;
import com.zhiqiyun.open.core.enmus.PasswordType;
import com.zhiqiyun.open.core.enmus.UserState;
import com.zhiqiyun.open.core.models.user.*;
import com.zhiqiyun.open.core.service.*;
import com.zhiqiyun.open.mvc.Result;
import com.zhiqiyun.open.mvc.manager.params.QueryLoginLogParam;
import com.zhiqiyun.open.mvc.manager.params.QueryOperateLogParams;
import com.zhiqiyun.open.mvc.manager.params.QueryUserParam;
import com.zhiqiyun.open.mvc.manager.params.SaveUserParam;
import com.zhiqiyun.open.utils.RandomUtil;
import com.zhiqiyun.open.utils.ServletContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author jtoms
 */
@RestController
@RequestMapping("/user")
public class UserInfoController {

    @Autowired
    private UserBaseInfoService userBaseInfoService;

    @Autowired
    private UserOperateLogService userOperateLogService;

    @Autowired
    private UserLoginLogService userLoginLogService;

    @Autowired
    private RoleInfoService roleInfoService;

    @Autowired
    private OauthService oauthService;

    @Permission(value = "oauth.user.find", tags = "查询系统所有用户")
    @PostMapping("/findPage")
    public Result findRolePage(@RequestBody QueryUserParam params) {

        Page<UserBaseInfo> page = params.getPage();
        page.addOrder(OrderItem.desc("id"));
        QueryWrapper<UserBaseInfo> queryWrapper = new QueryWrapper<>();

        if (params.getId() != null) {
            queryWrapper.eq("id", params.getId());
        }
        if (StringUtils.isNotBlank(params.getNickName())) {
            queryWrapper.like("nick_name", params.getNickName());
        }
        if (params.getState() != null) {
            queryWrapper.eq("state", params.getState());
        }
        if (params.getGender() != null) {
            queryWrapper.eq("gender", params.getGender());
        }
        if (params.getRegisterTime() != null) {
            queryWrapper.between("register_time", params.getRegisterTime().getStatDate(), params.getRegisterTime().getEndDate());
        }

        Page<UserBaseInfo> resultData = this.userBaseInfoService.page(page, queryWrapper);

        List<Map<String, Object>> listData = new ArrayList<>();
        for (UserBaseInfo info : resultData.getRecords()) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("id", info.getId());
            dataMap.put("nickName", info.getNickName());
            dataMap.put("registerTime", info.getRegisterTime());
            dataMap.put("registerIp", info.getRegisterIp());
            dataMap.put("avatar", info.getAvatar());
            dataMap.put("state", info.getState());
            dataMap.put("gender", info.getGender());
            List<UserLoginAccount> loginAccounts = this.userBaseInfoService.findLoginAccounts(info.getId());
            for (UserLoginAccount account : loginAccounts) {
                if (account.getAccountType() == null) {
                    continue;
                }
                dataMap.put(account.getAccountType().name(), account.getLoginAccount());
            }
            QueryWrapper<RoleInfo> queryRoleInfoWrapper = new QueryWrapper<>();
            queryRoleInfoWrapper.inSql("id", String.format("select role_id from user_role where uid=%s", info.getId()));
            List<RoleInfo> listRoles = this.roleInfoService.list(queryRoleInfoWrapper);
            dataMap.put("listRoles", listRoles);

            listData.add(dataMap);
        }

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("records", listData);
        dataMap.put("total", resultData.getTotal());
        dataMap.put("size", resultData.getSize());
        dataMap.put("current", resultData.getCurrent());
        return Result.instance(Result.Code.SUCCESS).setData(dataMap);
    }

    @Permission(value = "oauth.user.add", tags = "添加用户")
    @PostMapping("/save")
    public Result save(@Valid @RequestBody SaveUserParam param) throws Exception {
        return this.insertOrUpdate(null, param);
    }

    @Permission(value = "oauth.user.edit", tags = "修改用户")
    @PostMapping("/updateById")
    public Result updateById(Long id, @Valid @RequestBody SaveUserParam param) throws Exception {
        if (id == null || id <= 0) {
            return Result.instance("数据异常，请刷新页面后再试");
        }
        return this.insertOrUpdate(id, param);
    }

    private Result insertOrUpdate(Long uid, SaveUserParam param) throws Exception {
        List<UserLoginAccount> loginAccounts = new ArrayList<>();

        if (StringUtils.isNotBlank(param.getMp())) {
            UserLoginAccount mpAccount = this.userBaseInfoService.findLoginAccount(param.getMp(), AccountType.mp);
            if (mpAccount != null && !mpAccount.getUid().equals(uid)) {
                return Result.instance("手机号已被其他用户使用，请使更换手机号");
            }
            loginAccounts.add(new UserLoginAccount(param.getMp(), AccountType.mp));
        }

        if (StringUtils.isNotBlank(param.getEmail())) {
            UserLoginAccount emailAccount = this.userBaseInfoService.findLoginAccount(param.getEmail(), AccountType.email);
            if (emailAccount != null && !emailAccount.getUid().equals(uid)) {
                return Result.instance("邮箱已被其他用户使用，请使更换邮箱");
            }
            loginAccounts.add(new UserLoginAccount(param.getEmail(), AccountType.email));
        }

        UserBaseInfo userInfo = new UserBaseInfo();
        BeanUtils.copyProperties(param, userInfo);
        userInfo.setId(uid);
        userInfo.setRegisterIp(ServletContext.getRemoteIPAddress());
        String loginPassword = this.userBaseInfoService.insertOrUpdate(userInfo, loginAccounts, param.getListRoles());
        return Result.instance(Result.Code.MESSAGE_SUCCESS).setData(loginPassword);
    }

    @Permission(value = "oauth.user.disable", tags = "禁用用户")
    @PostMapping("/disableByIds")
    public Result disableByIds(@RequestBody List<Long> ids) {
        if (ids.contains(1000L)) {
            return Result.instance(Result.Code.MESSAGE_ERROR, "系统管理员不能禁用");
        }
        if (ids.isEmpty()) {
            return Result.instance(Result.Code.MESSAGE_ERROR, "请选择要禁用的用户");
        }
        for (Long uid : ids) {
            UserBaseInfo userInfo = new UserBaseInfo();
            userInfo.setId(uid);
            userInfo.setState(UserState.disable);
            this.userBaseInfoService.updateById(userInfo);
        }
        return Result.instance(Result.Code.MESSAGE_SUCCESS);
    }

    @Permission(value = "oauth.user.enable", tags = "启用用户")
    @PostMapping("/enabledByIds")
    public Result enabledByIds(@RequestBody List<Long> ids) {
        if (ids.isEmpty()) {
            return Result.instance(Result.Code.MESSAGE_ERROR, "请选择要启用的用户");
        }
        for (Long uid : ids) {
            UserBaseInfo userInfo = new UserBaseInfo();
            userInfo.setId(uid);
            userInfo.setState(UserState.normal);
            this.userBaseInfoService.updateById(userInfo);
        }
        return Result.instance(Result.Code.MESSAGE_SUCCESS);
    }

    @Permission(value = "oauth.user.reset.login.password", tags = "重置用户密码")
    @PostMapping("/resetLoginPasswordByIds")
    public Result resetLoginPasswordByIds(@RequestBody Long[] ids) {
        String password = RandomUtil.get(6);
        for (Long uid : ids) {
            String salt = RandomUtil.getSalt();
            String hashPassword = this.oauthService.generatePassword(password, salt);
            this.userBaseInfoService.updatePassword(uid, hashPassword, salt, PasswordType.login);
        }
        return Result.instance(Result.Code.SUCCESS).setData(password);
    }

    @Permission(value = "oauth.user.find", tags = "查询用户操作日志")
    @PostMapping("/findOperateLogPage")
    public Result findOperateLogPage(@RequestBody QueryOperateLogParams params) {
        Page<UserOperateLog> page = params.getPage();
        page.addOrder(OrderItem.desc("request_time"));

        QueryWrapper<UserOperateLog> queryWrapper = new QueryWrapper<>();
        if (params.getUid() != null) {
            queryWrapper.like("uid", params.getUid());
        }
        if (StringUtils.isNotBlank(params.getTags())) {
            queryWrapper.like("tags", params.getTags());
        }
        if (StringUtils.isNotBlank(params.getRequestIp())) {
            queryWrapper.eq("request_ip", params.getRequestIp());
        }
        if (StringUtils.isNotBlank(params.getRequestUrl())) {
            queryWrapper.like("request_url", params.getRequestUrl());
        }
        if (StringUtils.isNotBlank(params.getRequestParams())) {
            queryWrapper.like("request_params", params.getRequestParams());
        }
        if (StringUtils.isNotBlank(params.getRequestData())) {
            queryWrapper.like("request_data", params.getRequestData());
        }
        if (params.getRequestTime() != null) {
            queryWrapper.between("request_time", params.getRequestTime().getStatDate(), params.getRequestTime().getEndDate());
        }
        Page<UserOperateLog> resultData = this.userOperateLogService.page(page, queryWrapper);
        for (UserOperateLog operateLog : resultData.getRecords()) {
            UserBaseInfo userBaseInfo = this.userBaseInfoService.getById(operateLog.getUid());
            if (userBaseInfo != null) {
                operateLog.setNickName(userBaseInfo.getNickName());
            }
        }
        return Result.instance(Result.Code.SUCCESS).setData(resultData);
    }

    @Permission(value = "oauth.user.find", tags = "查询用户登录日志")
    @PostMapping("/findLoginLogPage")
    public Result findLoginLogPage(@RequestBody QueryLoginLogParam params) {
        Page<UserLoginLog> page = params.getPage();
        page.addOrder(OrderItem.desc("login_time"));
        QueryWrapper<UserLoginLog> queryWrapper = new QueryWrapper<>();
        Page<UserLoginLog> resultData = this.userLoginLogService.page(page, queryWrapper);
        return Result.instance(Result.Code.SUCCESS).setData(resultData);
    }

    @Permission(tags = "搜索用户信息")
    @PostMapping(value = "/findSelectAccounts")
    public Result findSelectAccounts(String searchKey) {
        List<Map<String, Object>> listData = this.userBaseInfoService.findSelectAccounts(searchKey);
        return Result.instance(Result.Code.SUCCESS).setData(listData);
    }
}
