package com.njzscloud.dispose.sys.user.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.mp.support.PageParam;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.common.security.support.UserDetail;
import com.njzscloud.common.security.util.EncryptUtil;
import com.njzscloud.common.security.util.SecurityUtil;
import com.njzscloud.common.wechat.WechatUtil;
import com.njzscloud.common.wechat.param.Code2SessionParam;
import com.njzscloud.common.wechat.result.Code2SessionResult;
import com.njzscloud.dispose.cst.customer.constant.IdentityCategory;
import com.njzscloud.dispose.cst.customer.pojo.param.AddCustomerParam;
import com.njzscloud.dispose.cst.customer.pojo.result.AddCustomerResult;
import com.njzscloud.dispose.cst.customer.service.CustomerService;
import com.njzscloud.dispose.cst.driver.pojo.entity.DriverEntity;
import com.njzscloud.dispose.cst.driver.service.DriverService;
import com.njzscloud.dispose.cst.org.pojo.param.AddOrgParam;
import com.njzscloud.dispose.finance.constant.AccountType;
import com.njzscloud.dispose.finance.pojo.entity.MoneyAccountEntity;
import com.njzscloud.dispose.finance.service.MoneyAccountService;
import com.njzscloud.dispose.sys.auth.service.AuthService;
import com.njzscloud.dispose.sys.role.pojo.entity.RoleEntity;
import com.njzscloud.dispose.sys.role.pojo.result.RoleDetailResult;
import com.njzscloud.dispose.sys.user.constant.Gender;
import com.njzscloud.dispose.sys.user.mapper.UserMapper;
import com.njzscloud.dispose.sys.user.pojo.entity.UserAccountEntity;
import com.njzscloud.dispose.sys.user.pojo.entity.UserEntity;
import com.njzscloud.dispose.sys.user.pojo.param.*;
import com.njzscloud.dispose.sys.user.pojo.result.UserAccountDetailResult;
import com.njzscloud.dispose.sys.user.pojo.result.UserDetailResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.njzscloud.common.security.contant.Constants.ROLE_ANONYMOUS;
import static com.njzscloud.common.security.contant.Constants.ROLE_AUTHENTICATED;
import static com.njzscloud.dispose.event.SysMittEvent.COERCE_LOGOUT;

/**
 * 用户信息表
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserService extends ServiceImpl<UserMapper, UserEntity> implements IService<UserEntity> {
    private final UserAccountService userAccountService;
    private final UserRoleService userRoleService;
    private final CustomerService customerService;
    private final AuthService authService;
    private final MoneyAccountService moneyAccountService;
    private final DriverService  driverService;

    /**
     * 新增
     */
    @Transactional(rollbackFor = Exception.class)
    public Long add(AddUserParam addUserParam) {
        UserEntity userEntity = BeanUtil.copyProperties(addUserParam, UserEntity.class);
        this.save(userEntity);

        Long userEntityId = userEntity.getId();
        AddUserAccountParam addUserAccountParam = addUserParam.getAccount();

        userAccountService.add(addUserAccountParam.setUserId(userEntityId));

        userRoleService.bindUserRole(userEntityId, addUserParam.getRoles());

        return userEntityId;
    }

    /**
     * 修改
     */
    @Transactional(rollbackFor = Exception.class)
    public void modify(UserModifyParam userModifyParam) {
        Long id = userModifyParam.getId();
        UserEntity userEntity = this.getById(id);
        Assert.notNull(userEntity, () -> Exceptions.clierr("要修改的数据不存在"));

        userEntity = BeanUtil.copyProperties(userModifyParam, UserEntity.class);
        this.updateById(userEntity);

        userRoleService.bindUserRole(id, userModifyParam.getRoles());
    }

    /**
     * 删除
     */
    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        if (ids.contains(1L)) {
            throw Exceptions.clierr("不能删除管理员");
        }
        this.removeByIds(ids);
        userAccountService.delByUserIds(ids);
        userRoleService.delByUserIds(ids);
    }

    /**
     * 详情
     */
    public UserDetailResult detail(Long id) {
        UserEntity userEntity = this.getById(id);
        Assert.notNull(userEntity, "未查询到用户信息");
        UserDetailResult userDetailResult = BeanUtil.copyProperties(userEntity, UserDetailResult.class);
        UserAccountEntity userAccountEntity = userAccountService.getOne(Wrappers.<UserAccountEntity>lambdaQuery().eq(UserAccountEntity::getUserId, id));
        Assert.notNull(userAccountEntity, "未查询到用户信息");
        UserAccountDetailResult userAccountDetailResult = BeanUtil.copyProperties(userAccountEntity, UserAccountDetailResult.class);
        List<RoleDetailResult> roleDetailResults = userRoleService.listRole(id);
        return userDetailResult
            .setAccount(userAccountDetailResult)
            .setRoles(roleDetailResults);
    }

    /**
     * 分页查询
     */
    public PageResult<UserDetailResult> paging(PageParam pageParam, UserQueryParam userQueryParam) {
        String nickname = userQueryParam.getNickname();
        Gender gender = userQueryParam.getGender();
        String email = userQueryParam.getEmail();
        String phone = userQueryParam.getPhone();
        String username = userQueryParam.getUsername();
        Boolean disabled = userQueryParam.getDisabled();
        QueryWrapper<UserDetailResult> ew = Wrappers.<UserDetailResult>query()
            .eq("a.deleted", 0)
            .like(StrUtil.isNotBlank(nickname), "a.nickname", nickname)
            .eq(gender != null, "a.gender", gender)
            .like(StrUtil.isNotBlank(email), "a.email", email)
            .like(StrUtil.isNotBlank(phone), "a.phone", phone)
            .like(StrUtil.isNotBlank(username), "b.username", username)
            .eq(disabled != null, "b.disabled", disabled);
        return PageResult.of(baseMapper.paging(pageParam.toPage(), ew));
    }


    /**
     * 用户注册
     *
     * @param userRegisterParam 参数
     */
    @Transactional(rollbackFor = Exception.class)
    public UserDetail register(UserRegisterParam userRegisterParam) {
        UserRegisterParam.Account account = userRegisterParam.getAccount();
        AddUserAccountParam addUserAccountParam = BeanUtil.copyProperties(account, AddUserAccountParam.class);
        String wechatCode = account.getWechatCode();
        String openid = account.getOpenid();
        if (StrUtil.isNotBlank(wechatCode) && StrUtil.isBlank(openid)) {
            Code2SessionResult code2SessionResult = WechatUtil.code2Session(new Code2SessionParam().setJs_code(wechatCode));
            Assert.isTrue(code2SessionResult.isSucc(), () -> Exceptions.exception("微信校验失败"));
            addUserAccountParam.setWechatOpenid(code2SessionResult.getOpenid())
                .setWechatUnionid(code2SessionResult.getUnionid());
        } else {
            addUserAccountParam.setWechatOpenid(openid);
        }

        AddUserParam addUserParam = BeanUtil
            .copyProperties(userRegisterParam, AddUserParam.class)
            .setAccount(addUserAccountParam);

        UserRegisterParam.Customer customer = userRegisterParam.getCustomer();
        IdentityCategory identityCategory = customer.getIdentityCategory();

        RoleEntity role = baseMapper.getRole("ROLE_" + identityCategory.getVal());
        if (role != null) {
            HashSet<Long> roles = new HashSet<>();
            roles.add(role.getId());
            addUserParam.setRoles(roles);
        }

        Long userId = this.add(addUserParam);

        customer.setUserId(userId);
        UserRegisterParam.Org org = userRegisterParam.getOrg();
        AddCustomerResult customerResult = customerService.add(BeanUtil.copyProperties(customer, AddCustomerParam.class)
            .setAddOrgParam(BeanUtil.copyProperties(org, AddOrgParam.class)));

        if (IdentityCategory.SiJi.equals(identityCategory)) {
            // 添加司机信息到cst_driver
            DriverEntity driverEntity = new DriverEntity();
            driverEntity.setUserId(userId);
            driverEntity.setCustomerId(customerResult.getCustomerId());
            driverEntity.setOrgId(customerResult.getOrgId());
            driverEntity.setDrivingLicenceNo(org.getIdcard());
            driverEntity.setDriverName(account.getUsername());
            driverEntity.setPhone(account.getPhone());
            driverEntity.setDrivingLicence(org.getDrivingLicence());
            driverEntity.setLicenceStartTime(org.getLicenseStartTime());
            driverEntity.setLicenceEndTime(org.getLicenseEndTime());
            driverService.add(driverEntity);
        }
        // 添加账户信息
        MoneyAccountEntity moneyAccount = new MoneyAccountEntity();
        if (Boolean.TRUE.equals(customer.getManager())) {
            moneyAccount.setAccountType(AccountType.QiYe);
            moneyAccount.setOrgId(customerResult.getOrgId());
        } else {
            moneyAccount.setAccountType(AccountType.GeRen);
        }
        moneyAccount.setUserId(userId);
        moneyAccount.setCustomerId(customerResult.getCustomerId());
        moneyAccountService.add(moneyAccount);

        List<RoleDetailResult> roleDetailResults = userRoleService.listRole(userId);
        Set<String> roles = roleDetailResults.stream().map(RoleDetailResult::getRoleCode).collect(Collectors.toSet());
        roles.add(ROLE_AUTHENTICATED);
        roles.add(ROLE_ANONYMOUS);
        UserDetail userDetail = authService.my(userId, account.getClientCode())
            .setAuthWay(userRegisterParam.getAuthWay())
            .setRoles(roles);
        return SecurityUtil.registrationUser(userDetail);
    }

    /**
     * 修改密码
     */
    @Transactional(rollbackFor = Exception.class)
    public void modifyPasswd(ModifyPasswdParam modifyPasswdParam) {
        Long userId = SecurityUtil.currentUserId();
        userAccountService.modifyPasswd(userId, modifyPasswdParam);
    }

    public void disable(Long id, Boolean disable) {
        userAccountService.update(Wrappers.<UserAccountEntity>lambdaUpdate().eq(UserAccountEntity::getUserId, id)
            .set(UserAccountEntity::getDisabled, disable));
        COERCE_LOGOUT.emit(Collections.singletonList(id));
    }

    public void bindRole(BindRoleParam bindRoleParam) {
        Long id = bindRoleParam.getId();
        UserEntity userEntity = this.getById(id);
        Assert.notNull(userEntity, () -> Exceptions.clierr("用户不存在"));
        Set<Long> roles = bindRoleParam.getRoles();
        Assert.notEmpty(roles, () -> Exceptions.clierr("未指定角色"));
        userRoleService.bindUserRole(id, roles);
        COERCE_LOGOUT.emit(Collections.singletonList(id));
    }

    public void bindClient(Long id, Integer clientCode) {
        userAccountService.update(Wrappers.<UserAccountEntity>lambdaUpdate().eq(UserAccountEntity::getUserId, id)
            .set(UserAccountEntity::getClientCode, clientCode));
        COERCE_LOGOUT.emit(Collections.singletonList(id));
    }

    public void resetPasswd(Long id) {
        userAccountService.update(Wrappers.<UserAccountEntity>lambdaUpdate().eq(UserAccountEntity::getUserId, id)
            .set(UserAccountEntity::getSecret, EncryptUtil.encrypt("666666")));
        COERCE_LOGOUT.emit(Collections.singletonList(id));
    }
}
