package com.jkcredit.invoice.hub.service.user;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jkcredit.invoice.hub.constant.CommonConstant;
import com.jkcredit.invoice.hub.constant.ExceptionMessage;
import com.jkcredit.invoice.hub.mapper.UserMapper;
import com.jkcredit.invoice.hub.model.dto.user.UserDto;
import com.jkcredit.invoice.hub.model.dto.userBalance.UserBalanceForMailDto;
import com.jkcredit.invoice.hub.model.po.user.UserPo;
import com.jkcredit.invoice.hub.model.vo.user.UserVO;
import com.jkcredit.invoice.hub.service.base.BaseService;
import com.jkcredit.invoice.hub.spi.lang.exception.ServiceException;
import com.jkcredit.invoice.hub.util.AssertUtils;
import com.jkcredit.invoice.hub.util.BeanUtil;
import com.jkcredit.invoice.hub.util.CommonUtil;
import com.jkcredit.invoice.hub.util.EncodeUtil;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @description:
 * @author: xusonglin
 * @create: 2020/1/2 10:01
 * @version: V1.0
 **/
@Slf4j
@Service
@Transactional(readOnly = true)
public class UserServiceImpl extends BaseService implements UserService {
    @Resource
    UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Optional<UserPo> getUserByUserName(String userName) {
        return userMapper.getUserByUserName(userName);
    }

    @Override
    public UserVO getUserById(Long id) throws ServiceException {
        UserVO userVo = new UserVO();
        UserPo userPo = userMapper.selectById(id);
        if (userPo != null) {
            BeanUtils.copyProperties(userPo, userVo);
        } else {
            throw new ServiceException(ExceptionMessage.USER_NOT_EXIST);
        }
        return userVo;
    }

    @Override
    public IPage<UserVO> getAllUsers(Page page, UserDto userDto) {
        // 数据库中查出的po分页集合
        IPage<UserPo> users = userMapper.getUsersPage(page, userDto);
        return users.convert(this::convert);
    }

    private UserVO convert(UserPo po) {
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(po, vo);
        // 将数据库存储的decimal转double
        if (po.getPrice() != null) {
            vo.setPrice(CommonUtil.parseDouble(po.getPrice()));
        }
        if (po.getBalance() != null) {
            vo.setBalance(CommonUtil.parseDouble(po.getBalance()));
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void saveUser(UserDto userDto) {
        validate(userDto);

        UserPo userPo = new UserPo();
        BeanUtil.copyProperties(userPo, userDto);

        userPo.setAppSecret(EncodeUtil.getAppSecret(userDto.getAppKey()));
        userPo.setCreateTime(new Date());
        userPo.setPassword(BCrypt.hashpw(userDto.getPassword(), BCrypt.gensalt()));

        try {
            userMapper.insert(userPo);
        } catch (Exception e) {
            log.error("新增用户失败，失败原因：{}", e.getMessage());
            throw new ServiceException("新增用户失败");
        }
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public Boolean updateUser(@RequestParam UserDto userDto) {
        validate(userDto);

        UserPo userPo = userMapper.getUserById(userDto.getId());
        // todo 此方法需要完善，完善后不需要逐行if判断
        AssertUtils.assertNotNull(userPo, CommonConstant.USER_NOT_EXIST);

        if (!StringUtil.isNullOrEmpty(userDto.getPassword())) {
            userPo.setPassword(BCrypt.hashpw(userDto.getPassword(), BCrypt.gensalt()));
        }
        if (!StringUtil.isNullOrEmpty(userDto.getCompany())) {
            userPo.setCompany(userDto.getCompany());
        }
        if (!StringUtil.isNullOrEmpty(userDto.getContactName())) {
            userPo.setContactName(userDto.getContactName());
        }
        if (!StringUtil.isNullOrEmpty(userDto.getTelephone())) {
            userPo.setTelephone(userDto.getTelephone());
        }
        if (userDto.getPrice() != null) {
            userPo.setPrice(userDto.getPrice());
        }
        if (userDto.getStatus() != null) {
            userPo.setStatus(userDto.getStatus());
        }
        userPo.setUpdateTime(new Date());
        if (userMapper.updateById(userPo) == 1) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("appSecret", userPo.getAppSecret());
            jsonObject.put("userId", userPo.getId().toString());
            jsonObject.put("status", userPo.getStatus().toString());
            redisTemplate.opsForValue().set(CommonConstant.INVOICE_HUB_USER_APPKEY + userPo.getAppKey(), jsonObject);
            return true;
        } else {
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void deleteUser(Long id) {
        UserPo userPo = userMapper.getUserById(id);
        if (userPo == null) {
            throw new ServiceException(ExceptionMessage.USER_NOT_EXIST);
        } else {
            userPo.setActivated(CommonConstant.ACTIVATED_DELETED);
            try {
                userMapper.updateById(userPo);
            } catch (Exception e) {
                log.error("删除用户失败，失败原因：{}", e.getMessage());
                throw new ServiceException("删除用户失败");
            }
        }
    }

    @Override
    public UserPo getUserByAppKey(String appKey) {
        return userMapper.getUserByAppKey(appKey);
    }

    @Override
    public UserDto getUser(Long id) {
        UserDto userDto = new UserDto();
        UserPo userPo = userMapper.getUserById(id);
        if (userPo != null) {
            BeanUtils.copyProperties(userPo, userDto);
        } else {
            throw new ServiceException(ExceptionMessage.USER_NOT_EXIST);
        }
        return userDto;
    }

    @Override
    public List<UserBalanceForMailDto> getUserBalance() {
        List<UserBalanceForMailDto> dtoList = new ArrayList<>();
        List<UserPo> userPoList = userMapper.getUserBalance();
        for (UserPo userPo : userPoList) {
            UserBalanceForMailDto dto = new UserBalanceForMailDto();
            BeanUtils.copyProperties(userPo, dto);
            dto.setBalance(userPo.getBalance().setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            dtoList.add(dto);
        }
        return dtoList;
    }
}
