package com.pcloud.book.advertising.biz.impl;

import com.pcloud.book.advertising.biz.BmBiz;
import com.pcloud.book.advertising.dao.AdvertisingDistributionBookDao;
import com.pcloud.book.advertising.dao.AdvertisingSpaceDao;
import com.pcloud.book.advertising.dao.BmOptionDao;
import com.pcloud.book.advertising.dao.BmOptionItemDao;
import com.pcloud.book.advertising.dao.BmRegisterDao;
import com.pcloud.book.advertising.dao.BmRegisterItemDao;
import com.pcloud.book.advertising.dto.AdvertisingSpaceDTO;
import com.pcloud.book.advertising.dto.BmRegisterDTO;
import com.pcloud.book.advertising.dto.BmRegisterItemDTO;
import com.pcloud.book.advertising.dto.OptionType;
import com.pcloud.book.advertising.entity.AdvertisingBmOption;
import com.pcloud.book.advertising.entity.AdvertisingBmOptionItem;
import com.pcloud.book.advertising.entity.AdvertisingBmRegister;
import com.pcloud.book.advertising.entity.AdvertisingBmRegisterItem;
import com.pcloud.book.advertising.entity.AdvertisingDistributionBook;
import com.pcloud.book.advertising.entity.AdvertisingSpace;
import com.pcloud.book.advertising.enums.AdPositionEnum;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.consumer.user.ChannelConsr;
import com.pcloud.book.group.dao.BookGroupDao;
import com.pcloud.book.group.entity.BookGroup;
import com.pcloud.book.util.common.ExcelUtils;
import com.pcloud.common.entity.UploadResultInfo;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.exceptions.ExportException;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.aliyun.OssUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.readercenter.wechat.entity.WechatUser;

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

/**
 * @描述：报名
 * @作者：zhuyajie
 * @创建时间：20:04 2019/6/27
 * @版本：1.0
 */
@Component("bmBiz")
public class BmBizImpl implements BmBiz {

    private static final Logger LOGGER = LoggerFactory.getLogger(BmBizImpl.class);

    @Autowired
    private BmOptionDao bmOptionDao;
    @Autowired
    private BmOptionItemDao bmOptionItemDao;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private BmRegisterDao bmRegisterDao;
    @Autowired
    private BmRegisterItemDao bmRegisterItemDao;
    @Autowired
    private AdvertisingSpaceDao advertisingSpaceDao;
    @Autowired
    private BookGroupDao bookGroupDao;
    @Autowired
    private ChannelConsr channelConsr;
    @Autowired
    private AdvertisingDistributionBookDao distributionBookDao;

    /**
     * 获取报名商品选项类型
     */
    @Override
    public List<OptionType> getOptionType() throws BizException {
        List<OptionType> list = new ArrayList<>();
        OptionType optionType = new OptionType("input", "文本域（读者最多输入50字）");
        list.add(optionType);
        optionType = new OptionType("textarea", "多行文本域（读者最多输入2000字）");
        list.add(optionType);
        optionType = new OptionType("radio", "单选按钮");
        list.add(optionType);
        optionType = new OptionType("checkbox", "复选框");
        list.add(optionType);
        optionType = new OptionType("select", "选择（列表/菜单）");
        list.add(optionType);
        return list;
    }

    /**
     * 获取报名商品选项数据类型
     */
    @Override
    public List<OptionType> getOptionDataType() throws BizException {
        List<OptionType> list = new ArrayList<>();
        OptionType optionType = new OptionType("text", "不限");
        list.add(optionType);
        optionType = new OptionType("number", "数字");
        list.add(optionType);
        optionType = new OptionType("chinese", "汉字");
        list.add(optionType);
        optionType = new OptionType("english", "字母");
        list.add(optionType);
        optionType = new OptionType("email", "邮箱");
        list.add(optionType);
        optionType = new OptionType("date", "日期");
        list.add(optionType);
        optionType = new OptionType("mobile", "手机");
        list.add(optionType);
        optionType = new OptionType("phone", "固话");
        list.add(optionType);
        optionType = new OptionType("idcard", "身份证");
        list.add(optionType);
        return list;
    }

    /**
     * 新增选项列表
     */
    @Override
    public void addOptionList(List<AdvertisingBmOption> advertisingBmOptionList, Long cpaId) {
        if (ListUtils.isEmpty(advertisingBmOptionList) || null == cpaId) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "参数有误！");
        }
        List<Long> optionIds = bmOptionDao.getOptionIdsByCPAId(cpaId);
        for (AdvertisingBmOption bmOption : advertisingBmOptionList) {
            bmOption.setCpaId(cpaId);
            if (!ListUtils.isEmpty(optionIds) && null != bmOption.getId()) {//修改选项
                modifyOption(bmOption);
                optionIds.remove(bmOption.getId());
            } else {
                addOption(bmOption);
            }
        }
        if (!ListUtils.isEmpty(optionIds)) {//要删除的选项
            bmOptionDao.deleteByIds(optionIds);
            for (Long optionId : optionIds) {
                bmOptionItemDao.deleteByOptionId(optionId);
            }
        }
    }


    /**
     * 新增选项
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addOption(AdvertisingBmOption bmOption) throws BizException {
        if (null == bmOption.getCpaId() || StringUtil.isEmpty(bmOption.getItemInputType())
                || StringUtil.isEmpty(bmOption.getItemDataType()) || StringUtil.isEmpty(bmOption.getItemTitle())) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "参数有误！");
        }
        // 新增选项
        if (null == bmOption.getSeq()) {
            bmOption.setSeq(0L);
        }
        bmOption.setCreateUser(0L);
        bmOptionDao.insert(bmOption);
        Long optionId = bmOption.getId();
        // 添加选项清单
        addOptionItem(bmOption.getOptionItem(), bmOption.getCreateUser(), optionId);
        return optionId;
    }

    /**
     * 添加选项清单
     * @param itemList 选项清单列表
     * @param partyId  参与者ID
     * @param optionId 选项ID
     * @throws BizException
     */
    public void addOptionItem(List<AdvertisingBmOptionItem> itemList, Long partyId, Long optionId) throws BizException {
        if (ListUtils.isEmpty(itemList)) {
            return;
        }
        Long parentId = 0L;
        for (AdvertisingBmOptionItem item : itemList) {
            item.setOptionId(optionId);
            item.setCreateUser(partyId);
            item.setParentId(parentId);
            String text = item.getText();
            if (!StringUtil.isEmpty(text)) {
                item.setText(text);
            }
            bmOptionItemDao.insert(item);
        }
    }

    /**
     * 根据广告ID获取选项列表信息
     */
    @Override
    public List<AdvertisingBmOption> getByCPAId(Long cpaId) throws BizException {
        if (null == cpaId){
            return new ArrayList<>();
        }
        List<AdvertisingBmOption> list = bmOptionDao.getByCPAId(cpaId);
        return list;
    }

    /**
     * 修改选项
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyOption(AdvertisingBmOption bmOption) throws BizException {
        Long optionId = bmOption.getId();
        // 校验参数
        if (null == bmOption.getCpaId() || null == optionId || StringUtil.isEmpty(bmOption.getItemInputType())
                || StringUtil.isEmpty(bmOption.getItemDataType()) || StringUtil.isEmpty(bmOption.getItemTitle())) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "参数有误！");
        }
        // 修改选项
        bmOption.setUpdateUser(0L);
        bmOptionDao.update(bmOption);
        // 删除之前的选项清单
        bmOptionItemDao.deleteByOptionId(optionId);
        // 添加选项清单
        addOptionItem(bmOption.getOptionItem(), bmOption.getUpdateUser(), optionId);
    }

    @Override
    public void deleteByCPAId(Long cpaId) {
        List<Long> optionIds = bmOptionDao.getOptionIdsByCPAId(cpaId);
        if (ListUtils.isEmpty(optionIds)) {
            return;
        }
        for (Long optionId : optionIds) {
            bmOptionItemDao.deleteByOptionId(optionId);
        }
        bmOptionDao.deleteByIds(optionIds);
    }

    @Override
    public Long userSubmit(AdvertisingBmRegister bmRegister, Long wechatUserId) {
        // 检测参数
        Long adId = bmRegister.getAdId();
        if (adId == null) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "参数有误！");
        }
        AdvertisingSpace space = advertisingSpaceDao.getById(adId);
        if (null == space) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "广告位不存在或已删除！");
        }
        Long cpaId = space.getCpaId();
        List<AdvertisingBmRegisterItem> items = bmRegister.getBmRegisterItemList();
        if (ListUtils.isEmpty(items)) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "请填写表单");
        }
        Long mobilePhoneOptionId = bmOptionDao.getMobilePhoneOptionIdByCPA(cpaId);
        Optional<AdvertisingBmRegisterItem> itemOptional = items.stream().filter(s -> s != null && s.getOptionId() == mobilePhoneOptionId).findFirst();
        if (itemOptional.isPresent()) {// 存在
            AdvertisingBmRegisterItem registerItem = itemOptional.get();
            if (null != registerItem && !StringUtil.isEmpty(registerItem.getOptionValue())) {
                Integer count = bmRegisterItemDao.checkMobilePhone(adId, bmRegister.getFromType(), bmRegister.getFromId(), registerItem.getOptionValue());
                if (count > 0) {
                    throw new BookBizException(BookBizException.PARAM_IS_ERROR, "手机号已存在");
                }
            }
        }
        if ("WECHAT_GROUP".equals(bmRegister.getFromType())) {
            BookGroup bookGroup = bookGroupDao.getById(bmRegister.getBookGroupId());
            if (null == bookGroup) {
                return 0L;
            }
            bmRegister.setBookId(bookGroup.getBookId());
            bmRegister.setChannelId(bookGroup.getChannelId());
            bmRegister.setAdviserId(bookGroup.getCreateUser());
        } else {
            //投放书刊
            AdvertisingDistributionBook distributionBook = distributionBookDao.getChannelIdByAdIdBookId(adId, bmRegister.getBookId());
            if (null != distributionBook) {
                bmRegister.setChannelId(distributionBook.getChannelId());
                bmRegister.setAdviserId(distributionBook.getAdviserId());
            }
        }
        Long agentId = channelConsr.getParentId(bmRegister.getChannelId());
        bmRegister.setAgentId(agentId);
        WechatUser wechat = readerConsr.getWechatUser(wechatUserId);
        bmRegister.setNickName(wechat == null ? "" : wechat.getWechatUserNickname());
        bmRegisterDao.insert(bmRegister);
        Long registerId = bmRegister.getId();
        // 添加用户选项
        addRegisterItem(items, adId, wechatUserId, registerId);
        return registerId;
    }

    /**
     * 添加用户选项
     * @param items
     * @param adId
     * @param wechatUserId
     * @param registerId
     * @throws BizException
     */
    public void addRegisterItem(List<AdvertisingBmRegisterItem> items, Long adId, Long wechatUserId, Long registerId) throws BizException {
        if (ListUtils.isEmpty(items)) {
            return;
        }
        for (AdvertisingBmRegisterItem item : items) {
            item.setUserId(wechatUserId);
            item.setAdId(adId);
            item.setRegisterId(registerId);
            //多选单选选项id
            List<Long> optionItems = item.getOptionItemIds();
            if (ListUtils.isEmpty(optionItems)) {
                item.setOptionItemId(0L);
                bmRegisterItemDao.insert(item);
            }else {
                for (Long optionItemId : optionItems) {
                    if (null == optionItemId) {
                        continue;
                    }
                    item.setOptionItemId(optionItemId);
                    String optionValue = bmOptionItemDao.getValueById(optionItemId);
                    item.setOptionValue(optionValue);
                    bmRegisterItemDao.insert(item);
                }
            }
        }
    }

    /**
     * 微信端获取个人报名详情
     */
    @Override
    public List<BmRegisterDTO> getDetail4Wechat(Long adId, Long wechatUserId, Long qrcodeId) throws BizException {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("adId", adId);
        paramMap.put("wechatUserId", wechatUserId);
        paramMap.put("qrcodeId", qrcodeId);
        List<BmRegisterDTO> result = bmRegisterDao.getDetailByUser(paramMap);
        return result;

    }

    @Override
    public Long getRegisterCountByAdId(Long adId, String statisMonth, Long bookId, Long adviserId, Long channelId) {
        return bmRegisterDao.getRegisterCountByAdId(adId, statisMonth, bookId, adviserId, channelId);
    }

    @Override
    public Long getRegisterCountByAdIdQrcodeId(Long adId, String statisMonth, Long qrcodeId) {
        return bmRegisterDao.getRegisterCountByAdIdQrcodeId(adId, statisMonth, qrcodeId);
    }

    @Override
    public Long getRegisterCountByAdIds(List<Long> adIdList) {
        if (ListUtils.isEmpty(adIdList)){
            return 0L;
        }
        return bmRegisterDao.getRegisterCountByAdIds(adIdList);
    }

    @Override
    public Map<String, Object> exportRegisterInfoByAdId(Long adId, Long qrcodeId, String statisMonth, Long bookId, Long adviserId, Long channelId){
        AdvertisingSpaceDTO spaceDTO = advertisingSpaceDao.getDTOById(adId);
        if (null == spaceDTO) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "广告位不存在！");
        }
        List<BmRegisterDTO> registerDtos = new ArrayList<>();
        if (AdPositionEnum.WECHAT_GROUP_MSG.positionCode.equals(spaceDTO.getAdPosition())) {
            registerDtos = bmRegisterDao.getRegisterInfoListByAdIdQrcodeId(adId, statisMonth, qrcodeId);
        } else {
            registerDtos = bmRegisterDao.getRegisterInfoListByAdId(adId, statisMonth, bookId, adviserId, channelId);
        }
        if (ListUtils.isEmpty(registerDtos)) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "无报名信息！");
        }
        Map<String, Object> result = new HashMap<>();
        try {
            String title = spaceDTO.getAdName() + "-客户信息";
            List<AdvertisingBmOption> optionList = bmOptionDao.getByCPAId(spaceDTO.getCpaId());
            List<String> rowsNameList = new ArrayList<>();
            rowsNameList.add("序号");
            rowsNameList.add("报名人");
            rowsNameList.add("报名时间");
            for (int t = 0; t < optionList.size(); t++) {
                AdvertisingBmOption option = optionList.get(t);
                rowsNameList.add(option.getItemTitle());
            }
            String[] rowsName = rowsNameList.toArray(new String[0]);
            String filePath = exportRegisterInfo(title, rowsName, optionList, registerDtos);
            result.put("fileName", title);
            result.put("filePath", filePath);
            return result;
        } catch (DataAccessException e) {
            LOGGER.error("导出用户信息时【exportRegisterInfoByMaster】" + e.getMessage(), e);
            throw new BookBizException(BookBizException.ERROR, "导出注册用户相关信息时出现异常");
        } catch (Exception e) {
            LOGGER.error("调用commoncenter生成Excel异常:" + e.getMessage(), e);
            throw new BookBizException(BookBizException.ERROR, "导出失败，请稍后重试");

        }
    }

    /**
     * excel数据导出
     */
    private String exportRegisterInfo(String title, String[] rowsName, List<AdvertisingBmOption> optionList,List<BmRegisterDTO> registerDtos) {
        LOGGER.info("导出相关信息：registerDtos=" + registerDtos + ",optionList=" + optionList);
        SXSSFWorkbook wb = new SXSSFWorkbook(200);
        int columnNum = rowsName.length;
        int rowIndex = 0;
        SXSSFRow row;
        SXSSFCell cell;
        //设置表头样式
        CellStyle headerStyle = ExcelUtils.getColumnTopStyle(wb);
        SXSSFSheet sheet = wb.createSheet();
        row = sheet.createRow(rowIndex);
        cell = row.createCell(0);
        //合并前两行
        sheet.addMergedRegion(new CellRangeAddress(rowIndex, ++rowIndex, 0, columnNum - 1));
        cell.setCellStyle(headerStyle);
        cell.setCellValue(title);
        //设置属性
        row = sheet.createRow(++rowIndex);
        for (int i = 0; i < rowsName.length; ++i) {
            sheet.setColumnWidth(i, 20 * 256);
            cell = row.createCell(i);
            cell.setCellStyle(headerStyle);
            cell.setCellValue(rowsName[i]);
        }
        //设置数据样式
        CellStyle dataStyle = ExcelUtils.getDataStyle(wb);
        dataStyle.setAlignment(HorizontalAlignment.CENTER);

        //准备初始数据
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        int k = 1;
        if (!ListUtils.isEmpty(registerDtos)) {
            //excel数据准备
            this.exportExcelByDataList(registerDtos, dataStyle, k, rowIndex, sheet, optionList, df);
        }
        //上传文件
        String fileUrl = "";
        try {
            String UID = UUID.randomUUID().toString();
            String path = UID + ".xlsx";
            FileOutputStream fileOut = new FileOutputStream(path);
            wb.write(fileOut);
            fileOut.flush();
            fileOut.close();
            wb.close();
            UploadResultInfo uploadResultInfo = OssUtils.uploadLocalFile(path, "xlsx");
            fileUrl = uploadResultInfo.getUrl();
            LOGGER.info("=======fileUrl==========" + OssUtils.urlAddKeyLong(fileUrl));
            new File(path).delete();
        } catch (FileNotFoundException e) {
            LOGGER.error("临时文件Excel路径找不到" + e.getMessage(), e);
            throw new ExportException(BookBizException.ERROR, "导出Excel失败");
        } catch (IOException e) {
            LOGGER.error("生成临时文件Excel异常" + e.getMessage(), e);
            throw new ExportException(BookBizException.ERROR, "导出Excel失败");
        }
        return fileUrl;
    }

    /**
     * excel数据导出
     */
    private void exportExcelByDataList(List<BmRegisterDTO> registerDtos, CellStyle dataStyle, int k, int rowIndex, SXSSFSheet sheet, List<AdvertisingBmOption> optionList, SimpleDateFormat df) {
        LOGGER.info("excel数据导出");
        for (BmRegisterDTO registerDto : registerDtos) {
            SXSSFRow srow = sheet.createRow(++rowIndex);
            SXSSFCell cell0 = srow.createCell(0);
            cell0.setCellStyle(dataStyle);
            cell0.setCellValue(k++);

            SXSSFCell cell1 = srow.createCell(1);
            cell1.setCellStyle(dataStyle);
            cell1.setCellValue(registerDto.getNickName() == null ? "" : registerDto.getNickName());

            SXSSFCell cell2 = srow.createCell(2);
            cell2.setCellStyle(dataStyle);
            cell2.setCellValue(registerDto.getCreateTime() != null ? df.format(registerDto.getCreateTime()) : "");

            for (int m = 0; m < optionList.size(); m++) {
                AdvertisingBmOption appOption = optionList.get(m);
                Long optionId = appOption.getId();
                String optionValue = "";
                for (BmRegisterItemDTO dto : registerDto.getRegisterItemDTOS()) {
                    if (optionId.equals(dto.getOptionId())) {
                        optionValue = dto.getOptionValue();
                        optionValue = StringUtil.isEmpty(optionValue) ? "" : optionValue;
                    }
                }
                SXSSFCell cellm = srow.createCell(m + 3);
                cellm.setCellStyle(dataStyle);
                cellm.setCellValue(optionValue);
            }
        }
    }


    @Override
    public Long getRegisterUserNumByAdIdQrcodeId(Long qrcodeId, Long adId, String statisMonth) {
        return bmRegisterDao.getRegisterUserNumByAdIdQrcodeId(qrcodeId, adId, statisMonth);
    }

    @Override
    public Long getRegisterCountByBookId(Long bookId, Long adviserId, Long channelId, Long adId, String statisMonth) {
        return bmRegisterDao.getRegisterCountByBookId(bookId, adviserId, channelId, adId, statisMonth);
    }
}
