package com.kiisoo.ic.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kiisoo.ic.common.utils.MD5FileUtil;
import com.kiisoo.ic.constants.Constants;
import com.kiisoo.ic.domain.service.PrivilageDomainService;
import com.kiisoo.ic.store.entity.PoiStore;
import com.kiisoo.ic.store.entity.PoiStoreStaff;
import com.kiisoo.ic.store.mapper.PoiStoreDOMapper;
import com.kiisoo.ic.store.mapper.PoiStoreStaffDOMapper;
import com.kiisoo.ic.system.bean.AccountBean;
import com.kiisoo.ic.system.bean.ImportAccountErrorBean;
import com.kiisoo.ic.system.bean.ModifyAccountInput;
import com.kiisoo.ic.system.bean.SaveAccountInput;
import com.kiisoo.ic.system.entity.PrivilageAccountDO;
import com.kiisoo.ic.system.entity.PrivilageRoleDO;
import com.kiisoo.ic.system.entity.PrivilageUserDO;
import com.kiisoo.ic.system.enums.AccountEnum;
import com.kiisoo.ic.system.enums.RoleEnum;
import com.kiisoo.ic.system.mapper.PrivilageAccountDOMapper;
import com.kiisoo.ic.system.mapper.PrivilageRoleDOMapper;
import com.kiisoo.ic.system.mapper.PrivilageUserDOMapper;
import com.kiisoo.ic.system.service.PrivilageAccountService;
import com.kiisoo.ic.system.service.PrivilageUserRoleService;
import com.kiisoo.ic.system.service.PrivilageUserService;
import com.kiisoo.ic.webappmy.vo.StafferInfoVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.util.stream.Collectors.toList;

/**
 * 账号  服务实现类
 *
 * @author jinchaofan
 * @since 2020-02-19
 */
@Service
public class PrivilageAccountServiceImpl extends ServiceImpl<PrivilageAccountDOMapper, PrivilageAccountDO> implements PrivilageAccountService {

    /**
     * 账号 mapper
     */
    private final PrivilageAccountDOMapper privilageAccountDOMapper;

    /**
     * 用户 mapper
     */
    private final PrivilageUserDOMapper privilageUserDOMapper;

    /**
     * 用户 service
     */
    private final PrivilageUserService privilageUserService;

    /**
     * 用户角色关系 service
     */
    private final PrivilageUserRoleService privilageUserRoleService;

    /**
     * 域 service
     */
    private final PrivilageDomainService privilageDomainService;

    /**
     * 角色 mapper
     */
    private final PrivilageRoleDOMapper privilageRoleDOMapper;

    private final PoiStoreStaffDOMapper poiStoreStaffDOMapper;

    private final PoiStoreDOMapper poiStoreDOMapper;

    @Autowired
    public PrivilageAccountServiceImpl(PrivilageAccountDOMapper privilageAccountDOMapper, PrivilageUserDOMapper privilageUserDOMapper, PrivilageUserService privilageUserService, PrivilageUserRoleService privilageUserRoleService, PrivilageDomainService privilageDomainService, PrivilageRoleDOMapper privilageRoleDOMapper, PoiStoreStaffDOMapper poiStoreStaffDOMapper, PoiStoreDOMapper poiStoreDOMapper) {
        this.privilageAccountDOMapper = privilageAccountDOMapper;
        this.privilageUserDOMapper = privilageUserDOMapper;
        this.privilageUserService = privilageUserService;
        this.privilageUserRoleService = privilageUserRoleService;
        this.privilageDomainService = privilageDomainService;
        this.privilageRoleDOMapper = privilageRoleDOMapper;
        this.poiStoreStaffDOMapper = poiStoreStaffDOMapper;
        this.poiStoreDOMapper = poiStoreDOMapper;
    }

    @Override
    public IPage<AccountBean> listAccountInfo(int pageNum, int pageSize, String searchContent,
                                              Long roleId, Long shopId) {
        QueryWrapper<PrivilageAccountDO> wrapper = new QueryWrapper<>();

        //根据搜索内容和角色筛选查询
        Set<Long> accountIds = privilageAccountDOMapper.selectAccountIdByRoleAndSearchContent(searchContent, roleId);

        //根据店铺id查询
        if (shopId != null) {
            Set<Long> accountIdByShopId = privilageAccountDOMapper.selectAccountIdByShopId(shopId);
            //取交集
            List<Long> intersection = accountIds.stream().filter(accountIdByShopId::contains).collect(toList());
            //防报错
            intersection.add(-1L);
            wrapper.in("id", intersection);
        } else {
            //防报错
            accountIds.add(-1L);
            wrapper.in("id", accountIds);
        }

        wrapper.eq("type", AccountEnum.ACCOUNT_TYPE_SYSTEM.getType());
        wrapper.orderByDesc("id");
        //根据名字查询账号信息
        IPage<PrivilageAccountDO> privilageAccountDOIPage = privilageAccountDOMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
        return setAccountBean(privilageAccountDOIPage);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveAccount(SaveAccountInput saveAccountInput) {
        Long shopId = saveAccountInput.getShopId();
        List<PrivilageAccountDO> privilageAccountDOS = listAccountExists(saveAccountInput.getAccount());
        //存在跳过
        if (privilageAccountDOS != null && privilageAccountDOS.size() > 0) return false;
        //新增用户
        Long userId = privilageUserService.insertUser(saveAccountInput.getUserName());
        //新增账号
        insertAccount(saveAccountInput.getAccount(), saveAccountInput.getPassword(), userId);
        //绑定用户角色关系
        privilageUserRoleService.insertUserRoleRelation(userId, saveAccountInput.getRoleId());
        //店长维护用户店铺关系1.店长。4.导购
        if (shopId != null) {
            privilageDomainService.saveOneShop(userId, saveAccountInput.getStaffCode(), shopId, saveAccountInput.getType());
            return true;
        }
        PrivilageRoleDO privilageRoleDO = privilageRoleDOMapper.selectById(saveAccountInput.getRoleId());
        //运营人员维护全店铺域实体关系
        if (privilageRoleDO.getCode().equals(RoleEnum.ROLE_CODE_YYRY.getRoleCode())) {
            privilageDomainService.saveAllDate(userId, privilageRoleDO.getId());
        }
        return true;
    }

    @Override
    public List<PrivilageAccountDO> listAccountExists(String login) {
        Map<String, Object> selectAccountByLoginMap = new HashMap<>();
        selectAccountByLoginMap.put("login", login);
        return privilageAccountDOMapper.selectByMap(selectAccountByLoginMap);
    }

    @Override
    public Long insertAccount(String login, String password, Long userId) {
        //新增账号
        PrivilageAccountDO privilageAccountDO = new PrivilageAccountDO();
        privilageAccountDO.setLogin(login);
        privilageAccountDO.setPassword(MD5FileUtil.getMD5String(password));
        privilageAccountDO.setUserId(userId);
        privilageAccountDO.setType(AccountEnum.ACCOUNT_TYPE_SYSTEM.getType());
        privilageAccountDO.setStatus(AccountEnum.ACCOUNT_STATUS_NORMAL.getType());
        privilageAccountDOMapper.insert(privilageAccountDO);
        return privilageAccountDO.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeAccout(Long accountId, Long userId) {
        try {
            //删除账号
            privilageAccountDOMapper.deleteById(accountId);
            //删除用户
            privilageUserService.removeUser(userId);
            //删除用户角色关系
            privilageUserRoleService.removeUserRoleRelation(userId);
            //删除用户店铺和域关系
            privilageDomainService.removeUserEntity(userId);
            Long staffId = poiStoreStaffDOMapper.selectStaffIdByUserId(userId);
            //删除该用户店长，导购
            poiStoreStaffDOMapper.deleteById(staffId);
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public int modifyAccount(ModifyAccountInput modifyAccountInput) {
        //查询以前的账号名
        PrivilageAccountDO privilageAccountDO = privilageAccountDOMapper.selectById(modifyAccountInput.getAccountId());
        String oldLogin = privilageAccountDO.getLogin();
        //修改了账号
        if (!oldLogin.equals(modifyAccountInput.getAccount())) {
            List<PrivilageAccountDO> privilageAccountDOS = listAccountExists(modifyAccountInput.getAccount());
            if (privilageAccountDOS != null && privilageAccountDOS.size() > 0) {
                //账号名已存在
                return AccountEnum.ACCOUNT_MODIFY_STATUS_EXISTS.getType();
            }
        }
        //修改账号
        PrivilageAccountDO privilageAccountDO1 = new PrivilageAccountDO();
        privilageAccountDO1.setId(modifyAccountInput.getAccountId());
        privilageAccountDO1.setLogin(modifyAccountInput.getAccount());
        privilageAccountDO1.setUpdateTime(new Date());
        //修改了密码
        if (!privilageAccountDO.getPassword().equals(modifyAccountInput.getPassword())) {
            privilageAccountDO1.setPassword(MD5FileUtil.getMD5String(modifyAccountInput.getPassword()));
        }
        privilageAccountDOMapper.updateById(privilageAccountDO1);
        //修改用户名
        PrivilageUserDO privilageUserDO = new PrivilageUserDO();
        privilageUserDO.setId(modifyAccountInput.getUserId());
        privilageUserDO.setName(modifyAccountInput.getUserName());
        privilageUserDO.setUpdateTime(new Date());
        privilageUserDOMapper.updateById(privilageUserDO);

        //保存用户角色
        privilageUserRoleService.saveUserRole(modifyAccountInput.getUserId(), modifyAccountInput.getRoleId());

        Long shopId = modifyAccountInput.getShopId();
        Long userId = modifyAccountInput.getUserId();

        //先删
        privilageDomainService.removeUserEntity(userId);

        PrivilageRoleDO privilageRoleDO = privilageRoleDOMapper.selectById(modifyAccountInput.getRoleId());

        //店长维护用户店铺关系1.店长。4.导购
        if (shopId != null && (privilageRoleDO.getCode().equals(RoleEnum.ROLE_CODE_DZ.getRoleCode()) || privilageRoleDO.getCode().equals(RoleEnum.ROLE_CODE_DG.getRoleCode()))) {
            privilageDomainService.saveOneShop(userId, modifyAccountInput.getStaffCode(), shopId, modifyAccountInput.getType());
            return AccountEnum.ACCOUNT_MODIFY_STATUS_SUCCEED.getType();
        }
        //运营人员维护全店铺域实体关系
        else if (privilageRoleDO.getCode().equals(RoleEnum.ROLE_CODE_YYRY.getRoleCode())) {
            privilageDomainService.saveAllDate(userId, privilageRoleDO.getId());
        }

        return AccountEnum.ACCOUNT_MODIFY_STATUS_SUCCEED.getType();
    }

    /**
     * 设置账号查询bean
     *
     * @param privilageAccountDOIPage 账号信息
     * @return 有角色和用户信息的账号信息集合
     */
    private IPage<AccountBean> setAccountBean(IPage<PrivilageAccountDO> privilageAccountDOIPage) {
        IPage<AccountBean> resultList = new Page<>();
        List<AccountBean> list = new ArrayList<>();
        BeanUtils.copyProperties(privilageAccountDOIPage, resultList);
        //分页后的集合
        List<PrivilageAccountDO> records = privilageAccountDOIPage.getRecords();
        records.forEach(privilageAccountDO -> {
            Long userId = privilageAccountDO.getUserId();
            //用户和角色信息
            AccountBean accountBean = privilageAccountDOMapper.selectUserAndRoleInfo(userId);
            if (accountBean == null) return;
            String roleCode = accountBean.getRoleCode();
            //不是店长设置为全部
            if (!roleCode.equals(RoleEnum.ROLE_CODE_DZ.getRoleCode()) && !roleCode.equals(RoleEnum.ROLE_CODE_DG.getRoleCode())) {
                accountBean.setChannel(AccountBean.ALL_SHOP);
                accountBean.setShopName(AccountBean.ALL_SHOP);
            }
            //店长角色查询店铺信息和渠道
            if (roleCode.equals(RoleEnum.ROLE_CODE_DZ.getRoleCode()) || roleCode.equals(RoleEnum.ROLE_CODE_DG.getRoleCode())) {
                QueryWrapper<PoiStoreStaff> wrapper = new QueryWrapper<>();
                wrapper.eq("user_id", userId).last("limit 1");
                //店铺
                PoiStoreStaff shopNameByUserId = poiStoreStaffDOMapper.selectOne(wrapper);
                if (shopNameByUserId != null) {
                    PoiStore poiStore = poiStoreDOMapper.selectById(shopNameByUserId.getStoreId());
                    accountBean.setShopId(shopNameByUserId.getStoreId());
                    accountBean.setShopName(poiStore == null ? null : poiStore.getName());
                    accountBean.setStaffCode(shopNameByUserId.getStaffCode());
                }
            }
            accountBean.setAccount(privilageAccountDO.getLogin());
            accountBean.setAccountId(privilageAccountDO.getId());
            accountBean.setPassword(privilageAccountDO.getPassword());
            list.add(accountBean);
        });
        resultList.setTotal(privilageAccountDOIPage.getTotal());
        resultList.setRecords(list);
        return resultList;
    }

    /**
     * 上传账户信息
     *
     * @param files  文件
     * @param userId 用户
     * @return 是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public List<ImportAccountErrorBean> uploadAccount(MultipartFile[] files, Long userId) throws IOException {
        List<ImportAccountErrorBean> errorBeanList = new ArrayList<>();
        //创建用户所需信息记录
        List<SaveAccountInput> accountCreate = new ArrayList<>();
        if (files != null) {
            for (MultipartFile file : files) {
                if (!file.isEmpty()) {

                    String sourceName = file.getOriginalFilename();
                    InputStream fileInput = file.getInputStream();
                    // 解析excel
                    // Excel文件
                    Workbook book;

                    assert sourceName != null;
                    if (isExcel2007(sourceName)) {
                        book = new XSSFWorkbook(fileInput);
                    } else {
                        book = new HSSFWorkbook(fileInput);
                    }
                    // 得到第一个sheet
                    Sheet sheet = book.getSheetAt(0);
                    // 得到Excel的行数
                    int totalRows = sheet.getPhysicalNumberOfRows();


                    // 循环Excel行数,从第二行开始。标题不入库
                    for (int r = 2; r < totalRows; r++) {
                        Row row = sheet.getRow(r);
                        if (row == null) {
                            continue;
                        }
                        //用户
                        String user = getCellValue(row.getCell(0));
                        //用户不能为空
                        if (!StringUtils.isNotBlank(user)) {
                            ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                            errorBean.setError("第" + (r + 1) + "行用户不能为空，请输入完整重新导入！");
                            errorBeanList.add(errorBean);
                            continue;
                        }

                        //账户--判断唯一性
                        String account = getCellValue(row.getCell(1));
                        if (!StringUtils.isNotBlank(account)) {
                            ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                            errorBean.setError("第" + (r + 1) + "行账户不能为空，请输入完整重新导入！");
                            errorBeanList.add(errorBean);
                            continue;
                        } else {
                            QueryWrapper<PrivilageAccountDO> wrapper = new QueryWrapper<>();
                            wrapper.eq("login",account).last("limit 1");
                            PrivilageAccountDO accountDO = privilageAccountDOMapper.selectOne(wrapper);
                            if(accountDO != null){
                                ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                                errorBean.setError("第" + (r + 1) + "行账户已存在，请检查后重新导入！");
                                errorBeanList.add(errorBean);
                                continue;
                            }
                        }

                        //密码
                        String password = getCellValue(row.getCell(2));
                        if (!StringUtils.isNotBlank(password)) {
                            ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                            errorBean.setError("第" + (r + 1) + "行密码不能为空，请输入完整重新导入！");
                            errorBeanList.add(errorBean);
                            continue;
                        }

                        //角色
                        String roleName = getCellValue(row.getCell(3));
                        RoleEnum codeByName;
                        if (!StringUtils.isNotBlank(roleName)) {
                            ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                            errorBean.setError("第" + (r + 1) + "行角色不能为空，请输入完整重新导入该店铺！");
                            errorBeanList.add(errorBean);
                            continue;
                        } else {
                            codeByName = RoleEnum.getCodeByName(roleName);
                            //根据roleCode查询roleId
                            QueryWrapper<PrivilageRoleDO> wrapper = new QueryWrapper<>();
                            wrapper.eq("code",codeByName.getRoleCode()).last("limit 1");
                            PrivilageRoleDO privilageRoleDO = privilageRoleDOMapper.selectOne(wrapper);
                            if(null == privilageRoleDO){
                                ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                                errorBean.setError("第" + (r + 1) + "行角色代码输入有误，请检查后重新导入！");
                                errorBeanList.add(errorBean);
                            }
                        }

                        //可见店铺
                        String shopCode = getCellValue(row.getCell(4));
                        if(RoleEnum.ROLE_CODE_DZ.equals(codeByName) || RoleEnum.ROLE_CODE_DG.equals(codeByName)){
                            //只有这两个角色是需要填写店铺信息的
                            if (StringUtils.isBlank(shopCode)) {
                                ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                                errorBean.setError("第" + (r + 1) + "行可见店铺不能为空，请输入完整重新导入该店铺！");
                                errorBeanList.add(errorBean);
                                continue;
                            }else {
                                //根据店铺code查询店铺id
                                QueryWrapper<PoiStore> wrapper = new QueryWrapper<>();
                                wrapper.eq("code",shopCode).last("limit 1");
                                PoiStore poiStore = poiStoreDOMapper.selectOne(wrapper);
                                if(null == poiStore){
                                    ImportAccountErrorBean errorBean = new ImportAccountErrorBean();
                                    errorBean.setError("第" + (r + 1) + "行店铺代码输入有误，请检查后重新导入！");
                                    errorBeanList.add(errorBean);
                                }
                            }
                        }
                    }
                }
            }
        }
        if(errorBeanList.isEmpty()){
            //如果没有任何报错信息就执行添加操作，如果有报错信息就不执行添加操作
            accountCreate.forEach(this::saveAccount);
        }
        return errorBeanList;
    }

    @Override
    public Integer modifyAccountStatusById(Long accountId, Integer status) {
        PrivilageAccountDO privilageAccountDO = new PrivilageAccountDO();
        privilageAccountDO.setId(accountId);
        privilageAccountDO.setStatus(status);
        return privilageAccountDOMapper.updateById(privilageAccountDO);
    }

    @Override
    public int resetPassword(Long accountId) {
        String password = MD5FileUtil.getMD5String(Constants.PASSWORD_RESET);
        PrivilageAccountDO privilageAccountDO = new PrivilageAccountDO();
        privilageAccountDO.setId(accountId);
        privilageAccountDO.setPassword(password);
        privilageAccountDO.setUpdateTime(new Date());
        return privilageAccountDOMapper.updateById(privilageAccountDO);
    }

    @Override
    public int modifyUser(PrivilageUserDO privilageUserDO) {
        privilageUserDO.setUpdateTime(new Date());
        return privilageUserDOMapper.updateById(privilageUserDO);
    }

    /**
     * 描述：是否是2007的excel，返回true是2007
     */
    private static boolean isExcel2007(String filePath) {
        return filePath.matches("^.+\\.(?i)(xlsx)$");
    }

    /**
     * 读取cell单元格的值，如果为日期格式，进行转换
     *
     * @param cell 单元格
     * @return 单元格中的值(字符串形式)
     */
    private String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }

        if (cell.getCellTypeEnum() == CellType.STRING) {
            return String.valueOf(cell.getRichStringCellValue());
        } else if (cell.getCellTypeEnum() == CellType.BOOLEAN) {
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellTypeEnum() == CellType.FORMULA) {
            return cell.getCellFormula();
        } else if (cell.getCellTypeEnum() == CellType.NUMERIC) {
            short format = cell.getCellStyle().getDataFormat();

            SimpleDateFormat sdf;
            if (format == 14 || format == 31 || format == 57 || format == 58
                    || (176 <= format && format <= 178) || (182 <= format && format <= 196)
                    || (210 <= format && format <= 213) || (208 == format)) {
                // 日期
                sdf = new SimpleDateFormat("yyyy-MM-dd");
            } else if (format == 20 || format == 32 || 200 <= format && format <= 209) {
                // 时间
                sdf = new SimpleDateFormat("HH:mm");
            } else {
                // 不是日期格式
                return String.valueOf(cell.getNumericCellValue());
            }

            double value = cell.getNumericCellValue();
            Date date = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value);
            if (date == null) {
                return "";
            }
            String result;
            try {
                result = sdf.format(date);
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }
            return result;
        }

        return "";
    }
}
