package com.sptg.gateway.controller.common.excel;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.sptg.ad.api.entity.AdType;
import com.sptg.ad.api.feigns.AdTypeFeign;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.module.*;
import com.sptg.estate.api.dto.*;
import com.sptg.estate.api.entity.*;
import com.sptg.estate.api.feigns.*;
import com.sptg.gateway.controller.common.excel.tool.ExcelTool;
import com.sptg.gateway.controller.common.excel.tool.ReflectUtils;
import com.sptg.permissions.api.entity.Account;
import com.sptg.statistics.api.dto.StatisticsAdWatchDto;
import com.sptg.statistics.api.entity.StatisticsAdWatch;
import com.sptg.statistics.api.feigns.StatisticsAdWatchFeign;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidationHelper;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * title: ExportExcelController
 * package: com.sptg.gateway.controller.common.excel
 * description: 导出处理
 */
@RestController
@RequiredArgsConstructor
public class ExportExcelController {

    private final ResidentialFeign residentialFeign;
    private final UnitFeign unitFeign;
    private final RoomFeign roomFeign;
    private final UserFeign userFeign;
    private final StatisticsAdWatchFeign statisticsAdWatchFeign;
    private final AdTypeFeign adTypeFeign;
    private final AccessCardFeign accessCardFeign;
    private final ProjectFeign projectFeign;
    private final ProjectBookFeign projectBookFeign;
    private final ProjectCompletionFeign projectCompletionFeign;
    private final PositionFeign positionFeign;
    private final DeviceInstallationFeign deviceInstallationFeign;
    private final DeviceTestFeign deviceTestFeign;

    private final static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 功能描述:将导入小区时产生错误的小区数据导出
     *
     * @param httpServletResponse
     */
    public void exportErrorResidential(List<ResidentialDto> list, HttpServletResponse httpServletResponse) {
        List<ResidentialImportModule> residentialImportModuleList = new ArrayList<>();
        list.parallelStream().forEach(
                residentialDto -> {
                    ResidentialImportModule residentialImportModule = new ResidentialImportModule();
//                    residentialImportModule.setEstateOrgCode(residentialDto.getEstateOrgCode());
//                    residentialImportModule.setAgentOrgCode(residentialDto.getAgentOrgCode());
                    residentialImportModule.setName(residentialDto.getName());
//                    residentialImportModule.setRegionProvince(residentialDto.getRegionProvince());
//                    residentialImportModule.setRegionCity(residentialDto.getRegionCity());
//                    residentialImportModule.setRegionArea(residentialDto.getRegionArea());
                    residentialImportModule.setAddress(residentialDto.getAddress());
                    residentialImportModule.setPersonName(residentialDto.getPersonName());
                    residentialImportModule.setPersonTel(residentialDto.getPersonTel());
                    residentialImportModule.setRemark(residentialDto.getRemark());
                    residentialImportModule.setImportErrorMsg(residentialDto.getImportErrorMsg());
                    residentialImportModuleList.add(residentialImportModule);
                }
        );

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        writeExcel(httpServletResponse, residentialImportModuleList, "小区导入错误记录" + sdf.format(new Date()), null, new ResidentialImportModule());
    }

    /**
     * 功能描述:将导入单元时产生错误的单元数据导出
     *
     * @param httpServletResponse
     */
    public void exportErrorUnit(List<UnitDto> list, HttpServletResponse httpServletResponse) {
        List<UnitImportModule> unitImportModuleList = new ArrayList<>();
        list.parallelStream().forEach(
                unitDto -> {
                    UnitImportModule unitImportModule = new UnitImportModule();

                    unitImportModule.setResidentialNumber(unitDto.getResidentialNumber());
                    unitImportModule.setName(unitDto.getName());
                    unitImportModule.setPersonName(unitDto.getPersonName());
                    unitImportModule.setPersonTel(unitDto.getPersonTel());
                    unitImportModule.setBuiltYear(unitDto.getBuiltYear());
                    unitImportModule.setPropertyNature(unitDto.getPropertyNature());
                    unitImportModule.setIncludingElevator(unitDto.getIncludingElevator());
                    unitImportModule.setRemark(unitDto.getRemark());
                    if (unitDto.getSerial() != null) {
                        unitImportModule.setSerial(unitDto.getSerial().toString());
                    }
                    unitImportModule.setImportErrorMsg(unitDto.getImportErrorMsg());


                    unitImportModuleList.add(unitImportModule);
                }
        );

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        writeExcel(httpServletResponse, unitImportModuleList, "单元导入错误记录" + sdf.format(new Date()), null, new UnitImportModule());
    }

    /**
     * 功能描述:将导入房间时产生错误的房间数据导出
     *
     * @param httpServletResponse
     */
    public void exportErrorRoom(List<RoomDto> list, HttpServletResponse httpServletResponse) {
        List<RoomImportModule> roomImportModuleList = new ArrayList<>();
        list.parallelStream().forEach(
                roomDto -> {
                    RoomImportModule roomImportModule = new RoomImportModule();
                    roomImportModule.setResidentialNumber(roomDto.getResidentialNumber());
                    roomImportModule.setUnitNumber(roomDto.getUnitNumber());
                    roomImportModule.setName(roomDto.getName());
                    roomImportModule.setHouseType(roomDto.getHouseType());
                    roomImportModule.setFloor(roomDto.getFloor());
                    roomImportModule.setOrientation(roomDto.getOrientation());
                    roomImportModule.setOrnament(roomDto.getOrnament());
                    roomImportModule.setArea(roomDto.getArea());
                    roomImportModule.setRemark(roomDto.getRemark());
                    if (roomDto.getSerial() != null) {
                        roomImportModule.setSerial(roomDto.getSerial().toString());
                    }
                    roomImportModule.setImportErrorMsg(roomDto.getImportErrorMsg());
                    roomImportModuleList.add(roomImportModule);
                }
        );

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        writeExcel(httpServletResponse, roomImportModuleList, "房间导入错误记录" + sdf.format(new Date()), null, new RoomImportModule());
    }

    /**
     * 功能描述:将导入住户时产生错误的住户数据导出
     *
     * @param httpServletResponse
     */
    public void exportErrorUser(List<UserDto> list, HttpServletResponse httpServletResponse) {
        List<UserImportModule> userImportModuleList = new ArrayList<>();
        list.parallelStream().forEach(
                userDto -> {
                    UserImportModule userImportModule = new UserImportModule();
                    userImportModule.setResidentialName(userDto.getResidentialName());
                    userImportModule.setUnitName(userDto.getUnitName());
                    userImportModule.setRoomName(userDto.getRoomName());
                    userImportModule.setName(userDto.getName());
                    userImportModule.setTel(userDto.getTel());

                    userImportModule.setSex(userDto.getSex() + "");
                    userImportModule.setType(userDto.getType() + "");
                    userImportModule.setIdCard(userDto.getIdCard());
                    userImportModule.setBirthPlace(userDto.getBirthPlace());
                    userImportModule.setRemark(userDto.getRemark());
                    userImportModule.setImportErrorMsg(userDto.getImportErrorMsg());

                    userImportModuleList.add(userImportModule);
                }
        );

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        writeExcel(httpServletResponse, userImportModuleList, "住户导入错误记录" + sdf.format(new Date()), null, new UserImportModule());
    }

    /**
     * 功能描述:将导入记名卡时产生错误的数据导出
     *
     * @param httpServletResponse
     */
    public void exportErrorUserCard(List<AccessCardDto> list, HttpServletResponse httpServletResponse) {
        List<UserAccessImportModule> userAccessImportModuleList = new ArrayList<>();
        list.parallelStream().forEach(
                accessCardDto -> {
                    UserAccessImportModule userAccessImportModule = new UserAccessImportModule();

                    userAccessImportModule.setResidentialNumber(accessCardDto.getResidentialNumber());
                    userAccessImportModule.setUnitNumber(accessCardDto.getUnitNumber());
                    userAccessImportModule.setHouseNumber(accessCardDto.getHouseNumber());
                    userAccessImportModule.setUserName(accessCardDto.getUserName());
                    userAccessImportModule.setCardNo(accessCardDto.getCardNo());
                    if( null!= accessCardDto.getBeginDate()){
                        userAccessImportModule.setBeginDate(accessCardDto.getBeginDate().toString());
                    }
                    if(null != accessCardDto.getEndDate()){
                        userAccessImportModule.setEndDate(accessCardDto.getEndDate().toString());
                    }


                    userAccessImportModule.setImportErrorMsg(accessCardDto.getImportErrorMsg());

                    userAccessImportModuleList.add(userAccessImportModule);
                }
        );

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        writeExcel(httpServletResponse, userAccessImportModuleList, "记名卡导入错误记录" + sdf.format(new Date()), null, new UserAccessImportModule());
    }

    /**
     * 功能描述:将导入不记名卡时产生错误的数据导出
     *
     * @param httpServletResponse
     */
    public void exportErrorAccessCard(List<AccessCardDto> list, HttpServletResponse httpServletResponse) {
        List<AccessCardImportModule> accessCardImportModuleList = new ArrayList<>();
        list.parallelStream().forEach(
                accessCardDto -> {
                    AccessCardImportModule accessCardImportModule = new AccessCardImportModule();
                    accessCardImportModule.setCardNo(accessCardDto.getCardNo());
                    if( null!= accessCardDto.getBeginDate()){
                        accessCardImportModule.setBeginDate(accessCardDto.getBeginDate().toString());
                    }
                    if(null != accessCardDto.getEndDate()){
                        accessCardImportModule.setEndDate(accessCardDto.getEndDate().toString());
                    }
                    accessCardImportModule.setResidentialNumber(accessCardDto.getResidentialNumber());
                    accessCardImportModule.setUnitNumber(accessCardDto.getUnitNumber());
                    accessCardImportModule.setHouseNumber(accessCardDto.getHouseNumber());
                    accessCardImportModule.setImportErrorMsg(accessCardDto.getImportErrorMsg());

                    accessCardImportModuleList.add(accessCardImportModule);
                }
        );

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        writeExcel(httpServletResponse, accessCardImportModuleList, "不记名卡导入错误记录" + sdf.format(new Date()), null, new AccessCardImportModule());
    }

    /**
     * 功能描述:导出小区
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportResidential(HttpServletResponse httpServletResponse, Account onLineUser) {
        ResidentialDto residentialDto = new ResidentialDto();
        residentialDto.setOrgPosition(onLineUser.getOrgPosition());
        List<Residential> residentialList = this.residentialFeign.findListByPosition(residentialDto).getList();
        List<ResidentialExportModule> list = new ArrayList<>();
        if (null != residentialList) {
            int size = residentialList.size();
            for (int i = 0; i < size; i++) {
                Residential residential = residentialList.get(i);
                ResidentialExportModule residentialExportModule = new ResidentialExportModule();
                BeanUtils.copyProperties(residential, residentialExportModule);
                if (null == residential.getTotalRoomNumber() || 0 == residential.getTotalRoomNumber()) {
                    residentialExportModule.setRate("0.00%");
                } else {
                    DecimalFormat df = new DecimalFormat("0.00");
                    residentialExportModule.setRate(df.format((float) (residential.getExistRoomCount() / residential.getTotalRoomNumber())) + "%");
                }
                list.add(residentialExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "小区记录", null, new ResidentialExportModule());
    }

    /**
     * 功能描述:导出单元
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportUnit(HttpServletResponse httpServletResponse, Account onLineUser) {
        UnitDto unitDto = new UnitDto();
        unitDto.setOrgPosition(onLineUser.getOrgPosition());
        List<Unit> unitList = this.unitFeign.findListByPosition(unitDto).getList();
        List<UnitExportModule> list = new ArrayList<>();
        if (null != unitList) {
            int size = unitList.size();
            for (int i = 0; i < size; i++) {
                Unit unit = unitList.get(i);
                UnitExportModule unitExportModule = new UnitExportModule();
                BeanUtils.copyProperties(unit, unitExportModule);
                list.add(unitExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "单元记录", null, new UnitExportModule());
    }

    /**
     * 功能描述:导出房间
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportRoom(HttpServletResponse httpServletResponse, Account onLineUser) {
        RoomDto roomDto = new RoomDto();
        roomDto.setOrgPosition(onLineUser.getOrgPosition());
        List<Room> roomList = this.roomFeign.findListByPosition(roomDto).getList();
        List<RoomExportModule> list = new ArrayList<>();
        if (null != roomList) {
            int size = roomList.size();
            for (int i = 0; i < size; i++) {
                Room room = roomList.get(i);
                RoomExportModule roomExportModule = new RoomExportModule();
                BeanUtils.copyProperties(room, roomExportModule);
                list.add(roomExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "房间记录", null, new RoomExportModule());
    }

    /**
     * 功能描述:导出住户
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportUser(HttpServletResponse httpServletResponse, Account onLineUser) {
        UserDto userDto = new UserDto();
        userDto.setOrgPosition(onLineUser.getOrgPosition());
        List<User> userList = this.userFeign.findListByPosition(userDto).getList();
        List<UserExportModule> list = new ArrayList<>();
        if (null != userList) {
            int size = userList.size();
            for (int i = 0; i < size; i++) {
                User user = userList.get(i);
                UserExportModule userExportModule = new UserExportModule();
                BeanUtils.copyProperties(user, userExportModule);
                userExportModule.setTypeName(this.getTypeNameByType(user.getType()));
                userExportModule.setSexName(this.getSexNameByUserSex(user.getSex()));
                userExportModule.setCreateTypeName(this.getCreateTypeNameByCreateType(user.getCreateType()));
                userExportModule.setCheckStateName(this.getCheckStateNameByCheckState(user.getCheckState()));
                list.add(userExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "住户记录", null, new UserExportModule());
    }

    /**
     * 功能描述:导出广告观看
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportAdWatch(HttpServletResponse httpServletResponse, Account onLineUser) {
        StatisticsAdWatchDto statisticsAdWatchDto = new StatisticsAdWatchDto();
        statisticsAdWatchDto.setOrgPosition(onLineUser.getOrgPosition());
        List<StatisticsAdWatch> adWatchList = this.statisticsAdWatchFeign.getAdWatchList(statisticsAdWatchDto);
        List<AdWatchExportModule> list = new ArrayList<>();
        if (null != adWatchList) {
            int size = adWatchList.size();
            for (int i = 0; i < size; i++) {
                StatisticsAdWatch adWatch = adWatchList.get(i);
                AdWatchExportModule adWatchExportModule = new AdWatchExportModule();
                BeanUtils.copyProperties(adWatch, adWatchExportModule);
                AdType adType = adTypeFeign.getAdTypeById(adWatch.getAdTypeId());
                if (adType != null) {
                    adWatchExportModule.setAdTypeName(adType.getName());
                }
                ResultBean<String> userNameBean = this.userFeign.getUserNameById(adWatch.getUserId());
                if (userNameBean != null) {
                    adWatchExportModule.setUserName(userNameBean.getData());
                }
                adWatchExportModule.setCreateDate(SDF.format(adWatch.getCreateDate()));
                list.add(adWatchExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "广告观看统计记录", null, new AdWatchExportModule());
    }

    /**
     * 功能描述:导出广告观看排行
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportAdWatchRank(HttpServletResponse httpServletResponse, Account onLineUser) {
        StatisticsAdWatchDto statisticsAdWatchRankDto = new StatisticsAdWatchDto();
        statisticsAdWatchRankDto.setOrgPosition(onLineUser.getOrgPosition());
        List<StatisticsAdWatch> adWatchRankList = this.statisticsAdWatchFeign.getAdWatchRankList(statisticsAdWatchRankDto);
        List<AdWatchRankExportModule> list = new ArrayList<>();
        if (null != adWatchRankList) {
            int size = adWatchRankList.size();
            for (int i = 0; i < size; i++) {
                StatisticsAdWatch adWatchRank = adWatchRankList.get(i);
                AdWatchRankExportModule adWatchRankExportModule = new AdWatchRankExportModule();
                BeanUtils.copyProperties(adWatchRank, adWatchRankExportModule);
                AdType adType = adTypeFeign.getAdTypeById(adWatchRank.getAdTypeId());
                if (adType != null) {
                    adWatchRankExportModule.setAdTypeName(adType.getName());
                }
                list.add(adWatchRankExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "广告观看统计排行记录", null, new AdWatchRankExportModule());
    }

    /**
     * 功能描述:导出住户统计
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportStatisticsUser(HttpServletResponse httpServletResponse, Account onLineUser) {
        ResidentialDto residentialDto = new ResidentialDto();
        residentialDto.setOrgPosition(onLineUser.getOrgPosition());
        List<Residential> statisticsUserCountList = this.residentialFeign.getStatisticsUserCountList(residentialDto);
        List<StatisticsUserExportModule> list = new ArrayList<>();
        if (null != statisticsUserCountList) {
            int size = statisticsUserCountList.size();
            for (int i = 0; i < size; i++) {
                Residential residential = statisticsUserCountList.get(i);
                StatisticsUserExportModule statisticsUserExportModule = new StatisticsUserExportModule();
                BeanUtils.copyProperties(residential, statisticsUserExportModule);
                list.add(statisticsUserExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "小区住户统计记录", null, new StatisticsUserExportModule());
    }

    /**
     * 功能描述:住户管理导出
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportUserAccess(HttpServletResponse httpServletResponse, Account onLineUser) {
        UserDto dto = new UserDto();
        dto.setOrgPosition(onLineUser.getOrgPosition());
        List<User> userList = this.userFeign.findListByPosition(dto).getList();
        List<UserAccessExportModule> list = new ArrayList<>();
        if (null != userList) {
            int size = userList.size();
            for (int i = 0; i < size; i++) {
                User user = userList.get(i);
                UserAccessExportModule userCardExportModule = new UserAccessExportModule();
                BeanUtils.copyProperties(user, userCardExportModule);
                AccessCardDto accessCardDto = new AccessCardDto();
                accessCardDto.setUserId(String.valueOf(user.getId()));
                accessCardDto.setType(OperationConstant.ZERO);
                List<AccessCard> accessCardList = this.accessCardFeign.getAccessCardByUserIdAndType(accessCardDto);
                if (null != accessCardList && !accessCardList.isEmpty()) {
                    userCardExportModule.setCardNo(accessCardList.get(0).getCardNo());
                }
                userCardExportModule.setCheckStateName(this.getCheckStateNameByCheckState(user.getCheckState()));
                list.add(userCardExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "住户出入管理记录", null, new UserAccessExportModule());
    }

    /**
     * 功能描述:卡管理导出
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportAccessCard(HttpServletResponse httpServletResponse, Account onLineUser) {
        AccessCardDto dto = new AccessCardDto();
        dto.setOrgPosition(onLineUser.getOrgPosition());
        List<AccessCard> accessCardList = this.accessCardFeign.findListByPosition(dto).getList();
        List<AccessCardExportModule> list = new ArrayList<>();
        if (null != accessCardList) {
            int size = accessCardList.size();
            for (int i = 0; i < size; i++) {
                AccessCard accessCard = accessCardList.get(i);
                AccessCardExportModule accessCardExportModule = new AccessCardExportModule();
                BeanUtils.copyProperties(accessCard, accessCardExportModule);
                accessCardExportModule.setCardDate(SDF.format(accessCard.getBeginDate()) + "-" + SDF.format(accessCard.getEndDate()));
                list.add(accessCardExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "卡管理记录", null, new AccessCardExportModule());
    }

    /**
     * 功能描述:实施项目导出
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportProject(HttpServletResponse httpServletResponse, Account onLineUser) {
        SimpleDateFormat SDF2 = new SimpleDateFormat("yyyy-MM");
        ProjectDto dto = new ProjectDto();
        dto.setOrgPosition(onLineUser.getOrgPosition());
        List<Project> projectList = this.projectFeign.findListByPosition(dto).getList();
        List<ProjectExportModule> list = new ArrayList<>();
        if (null != projectList) {
            int size = projectList.size();
            for (int i = 0; i < size; i++) {
                Project project = projectList.get(i);
                ProjectExportModule projectExportModule = new ProjectExportModule();
                BeanUtils.copyProperties(project, projectExportModule);
                projectExportModule.setNumber(String.valueOf(i + 1));
                projectExportModule.setSigningDate(project.getSigningDate() == null ? "" : SDF.format(project.getSigningDate()));
                Position position = this.positionFeign.findByProjectId(project.getId()).getData();
                if (null != position) {
                    projectExportModule.setPositionCreateDate(SDF.format(position.getCreateDate()));
                    int pillar = position.getPillar();
                    projectExportModule.setPositionPillar(pillar);
                    int wallHung = position.getWallHung();
                    projectExportModule.setPositionWallHung(wallHung);
                    projectExportModule.setPositionTotalCount(pillar + pillar);
                    projectExportModule.setPositionRainCover(position.getRainCover());
                }
                ProjectBook projectBook = this.projectBookFeign.findByProjectId(project.getId()).getData();
                if (null != projectBook) {
                    projectExportModule.setProjectBookAcceptanceDate(projectBook.getAcceptanceDate() == null ? "" : SDF2.format(projectBook.getAcceptanceDate()));
                    projectExportModule.setProjectBookDeliveryDate(projectBook.getDeliveryDate() == null ? "" : SDF2.format(projectBook.getDeliveryDate()));
                    if (projectBook.getBeginRectificationDate() != null) {
                        projectExportModule.setProjectBookRectificationDate(SDF2.format(projectBook.getBeginRectificationDate()) + " - " + SDF2.format(projectBook.getEndRectificationDate()));
                    }

                    projectExportModule.setProjectBookConstructionDate(projectBook.getConstructionDate() == null ? "" : SDF2.format(projectBook.getConstructionDate()));
                    if (projectBook.getBeginProductionDate() != null) {
                        projectExportModule.setProjectBookProductionDate(SDF2.format(projectBook.getBeginProductionDate()) + " - " + SDF2.format(projectBook.getEndProductionDate()));
                    }
                }
                ProjectCompletion projectCompletion = this.projectCompletionFeign.findByProjectId(project.getId()).getData();
                if (null != projectCompletion) {
                    projectExportModule.setProjectCompletionDate(projectCompletion.getCompletionDate() == null ? "" : SDF.format(projectCompletion.getCompletionDate()));
                    int pillar = projectCompletion.getPillar();
                    projectExportModule.setProjectCompletionPillar(pillar);
                    int wallHung = projectCompletion.getWallHung();
                    projectExportModule.setProjectCompletionWallHung(wallHung);
                    projectExportModule.setProjectCompletionTotalCount(pillar + wallHung);
                }
                list.add(projectExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "实施项目记录", null, new ProjectExportModule());
    }

    /**
     * 功能描述:设备定位导出
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportPosition(HttpServletResponse httpServletResponse, Account onLineUser) {
        PositionDto dto = new PositionDto();
        dto.setOrgPosition(onLineUser.getOrgPosition());
        List<Position> positionList = this.positionFeign.findListByPosition(dto).getList();
        List<PositionExportModule> list = new ArrayList<>();
        if (null != positionList) {
            int size = positionList.size();
            for (int i = 0; i < size; i++) {
                Position position = positionList.get(i);
                PositionExportModule positionExportModule = new PositionExportModule();
                BeanUtils.copyProperties(position, positionExportModule);
                positionExportModule.setCreateDate(SDF.format(position.getCreateDate()));
                positionExportModule.setTotal(position.getPillar() + position.getWallHung());
                positionExportModule.setCheckStateName(this.getCheckStateNameByCheckState(position.getCheckState()));
                list.add(positionExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "设备定位导出记录", null, new PositionExportModule());
    }

    /**
     * 功能描述:设备安装导出
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportDeviceInstallation(HttpServletResponse httpServletResponse, Account onLineUser) {
        DeviceInstallationDto dto = new DeviceInstallationDto();
        dto.setOrgPosition(onLineUser.getOrgPosition());
        List<DeviceInstallation> deviceInstallationList = this.deviceInstallationFeign.findListByPosition(dto).getList();
        List<DeviceInstallationExportModule> list = new ArrayList<>();
        if (null != deviceInstallationList) {
            int size = deviceInstallationList.size();
            for (int i = 0; i < size; i++) {
                DeviceInstallation deviceInstallation = deviceInstallationList.get(i);
                DeviceInstallationExportModule deviceInstallationExportModule = new DeviceInstallationExportModule();
                BeanUtils.copyProperties(deviceInstallation, deviceInstallationExportModule);
                deviceInstallationExportModule.setCreateDate(SDF.format(deviceInstallation.getCreateDate()));
                deviceInstallationExportModule.setCheckStateName(this.getCheckStateNameByCheckState(deviceInstallation.getCheckState()));
                PositionRecord positionRecord = deviceInstallation.getPositionRecord();
                if (null != positionRecord) {
                    deviceInstallationExportModule.setSpecificLocation(positionRecord.getInstallPath());
                    deviceInstallationExportModule.setDeviceTypeName(this.getDeviceTypeNameByDeviceType(positionRecord.getDeviceType()));
                }
                list.add(deviceInstallationExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "设备安装导出记录", null, new DeviceInstallationExportModule());
    }

    /**
     * 功能描述:设备检测导出
     *
     * @param httpServletResponse
     * @param onLineUser
     */
    public void exportDeviceTest(HttpServletResponse httpServletResponse, Account onLineUser) {
        DeviceTestDto dto = new DeviceTestDto();
        dto.setOrgPosition(onLineUser.getOrgPosition());
        List<DeviceTest> deviceTestList = this.deviceTestFeign.findListByPosition(dto).getList();
        List<DeviceTestExportModule> list = new ArrayList<>();
        if (null != deviceTestList) {
            int size = deviceTestList.size();
            for (int i = 0; i < size; i++) {
                DeviceTest deviceTest = deviceTestList.get(i);
                DeviceTestExportModule deviceTestExportModule = new DeviceTestExportModule();
                BeanUtils.copyProperties(deviceTest, deviceTestExportModule);
                deviceTestExportModule.setCreateDate(SDF.format(deviceTest.getCreateDate()));
                deviceTestExportModule.setCheckStateName(this.getCheckStateNameByCheckState(deviceTest.getCheckState()));
                DeviceInstallation deviceInstallation = deviceTest.getDeviceInstallation();
                if (null != deviceInstallation) {
                    deviceTestExportModule.setSerialNumber(deviceTest.getSerialNumber());
                    deviceTestExportModule.setResidentialName(deviceTest.getResidentialName());
                }
                PositionRecord positionRecord = deviceInstallation.getPositionRecord();
                if (null != positionRecord) {
                    deviceTestExportModule.setSpecificLocation(positionRecord.getInstallPath());
                    deviceTestExportModule.setDeviceTypeName(this.getDeviceTypeNameByDeviceType(positionRecord.getDeviceType()));
                }
                list.add(deviceTestExportModule);
            }
        }
        writeExcel(httpServletResponse, list, "设备检测导出记录", null, new DeviceTestExportModule());
    }

    /**
     * 导出 Excel ：一个 sheet，带表头
     *
     * @param response  HttpServletResponse
     * @param list      数据 list，每个元素为一个 BaseRowModel
     * @param fileName  导出的文件名
     * @param sheetName 导入文件的 sheet 名
     * @param object    映射实体类，Excel 模型
     */
    public void writeExcel(HttpServletResponse response, List<? extends BaseRowModel> list,
                           String fileName, String sheetName, BaseRowModel object) {

        ExcelWriter writer = new ExcelWriter(getOutputStream(fileName, response), ExcelTypeEnum.XLSX);
        if (list.size() > 50000) {
            List<? extends List<? extends BaseRowModel>> lt = Lists.partition(list, 50000);
            for (int i = 0; i < lt.size(); i++) {
                Sheet sheet = new Sheet((i + 1), 0, object.getClass());
                sheet.setSheetName(sheetName);
                writer.write(lt.get(i), sheet);
            }
        } else {
            Sheet sheet = new Sheet(1, 0, object.getClass());
            sheet.setSheetName(sheetName);
            writer.write(list, sheet);
        }
        writer.finish();
    }

    /**
     * 导出文件时为Writer生成OutputStream
     */
    private OutputStream getOutputStream(String fileName, HttpServletResponse response) {
        //创建本地文件
        String filePath = fileName + ".xlsx";
        File dbfFile = new File(filePath);
        OutputStream outputStream = null;
        try {
            if (!dbfFile.exists() || dbfFile.isDirectory()) {
                dbfFile.createNewFile();
            }
            fileName = new String(filePath.getBytes(), "ISO-8859-1");
            response.addHeader("Content-Disposition", "filename=" + fileName);
            outputStream = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dbfFile.exists()) {
                dbfFile.delete();
            }
        }
        return outputStream;
    }

    /**
     * 功能描述:获取住户类型
     *
     * @param type
     * @return String
     */
    private String getTypeNameByType(int type) {
        switch (type) {
            case 0:
                return "业主";
            case 1:
                return "成员";
            case 2:
                return "租客";
            default:
                return "业主";
        }
    }

    /**
     * 功能描述:获取住户性别
     *
     * @param sex
     * @return String
     */
    private String getSexNameByUserSex(int sex) {
        switch (sex) {
            case 0:
                return "未定义";
            case 1:
                return "男";
            case 2:
                return "女";
            default:
                return "未定义";
        }
    }

    /**
     * 功能描述:获取住户创建类型
     *
     * @param createType
     * @return String
     */
    private String getCreateTypeNameByCreateType(int createType) {
        switch (createType) {
            case 0:
                return "小程序添加";
            case 1:
                return "后台录入";
            case 2:
                return "后台导入";
            case 3:
                return "APP添加";
            default:
                return "";
        }
    }

    /**
     * 功能描述:获取审核状态
     *
     * @param checkState
     * @return String
     */
    private String getCheckStateNameByCheckState(int checkState) {
        switch (checkState) {
            case 0:
                return "待审核";
            case 1:
                return "审核通过";
            case 2:
                return "审核不通过";
            default:
                return "";
        }
    }


    private String getDeviceTypeNameByDeviceType(int deviceType) {
        switch (deviceType) {
            case 0:
                return "待审核";
            case 1:
                return "审核通过";
            case 2:
                return "审核不通过";
            default:
                return "";
        }
    }

    public void writeExcelWithArea(HttpServletResponse response, ArrayList<Object> objects, String fileName, String sheetName, BaseRowModel rowModel, boolean includeStreet) {
        // 查询所有的省名称
        List<String> provNameList = ExcelTool.makeProvNameList();
        // 整理数据，放入一个Map中，mapkey存放父地点，value 存放该地点下的子区域
        Map<String, List<String>> siteMap =  ExcelTool.makeSiteMap();
        // 获取实体类名称
        List<String> colummaNames = ReflectUtils.getColumnName(rowModel.getClass());

        // 创建一个excel
        Workbook book = new XSSFWorkbook();
        // 创建需要用户填写的数据页
        // 设计表头
        org.apache.poi.ss.usermodel.Sheet sheet1 = book.createSheet("sheet1");
        Row row0 = sheet1.createRow(0);

        for (int i = 0; i < colummaNames.size(); i++) {
            Cell cell = row0.createCell(i);
            RichTextString text = new XSSFRichTextString(colummaNames.get(i));
            cell.setCellValue(text);
            sheet1.setColumnWidth(i, 28 * 256);
        }

        //设置一下高度
        row0.setHeightInPoints(30);

        //创建一个专门用来存放地区信息的隐藏sheet页
        //因此也不能在现实页之前创建，否则无法隐藏。
        org.apache.poi.ss.usermodel.Sheet hideSheet = book.createSheet("site");
        book.setSheetHidden(book.getSheetIndex(hideSheet), true);

        XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper((XSSFSheet)sheet1);

        // 省规则
//		DataValidationConstraint provConstraint = dvHelper.createExplicitListConstraint(provNameList.toArray(new String[]{}));
        DataValidationConstraint provConstraint = dvHelper.createFormulaListConstraint("site!$B$1:$AF$1");
        CellRangeAddressList provRangeAddressList = new CellRangeAddressList(1, 50000, 0, 0);
        DataValidation provinceDataValidation = dvHelper.createValidation(provConstraint, provRangeAddressList);
        provinceDataValidation.createErrorBox("error", "请选择正确的省份");
        provinceDataValidation.setShowErrorBox(true);
        provinceDataValidation.setSuppressDropDownArrow(true);
        sheet1.addValidationData(provinceDataValidation);

        int rowId = 0;
        // 设置第一行，存省的信息
        Row proviRow = hideSheet.createRow(rowId++);
        proviRow.createCell(0).setCellValue("省列表");
        for(int i = 0; i < provNameList.size(); i ++){
            Cell proviCell = proviRow.createCell(i + 1);
            proviCell.setCellValue(provNameList.get(i));
        }
        // 将具体的数据写入到每一行中，行开头为父级区域，后面是子区域。
        Iterator<String> keyIterator = siteMap.keySet().iterator();
        while(keyIterator.hasNext()){
            String key = keyIterator.next();
            List<String> son = siteMap.get(key);

            Row row = hideSheet.createRow(rowId);
            row.createCell(0).setCellValue(key);
            for(int i = 0; i < son.size(); i ++){
                Cell cell = row.createCell(i + 1);
                cell.setCellValue(son.get(i));
            }

            // 添加名称管理器
            String range = ExcelTool.getRange(1, rowId + 1, son.size());
            Name name = book.createName();
            name.setNameName(key);
            String formula = "site!" + range;
            name.setRefersToFormula(formula);

            // 添加有效性规则
            // 市以规则，此处仅作一个示例
            // "INDIRECT($A$" + 2 + ")" 表示规则数据会从名称管理器中获取key与单元格 A2 值相同的数据，如果A2是浙江省，那么此处就是 浙江省下的区域信息。
            DataValidationConstraint formulaList = dvHelper.createFormulaListConstraint("INDIRECT(A" + (rowId + 1) + ")");
            CellRangeAddressList rangeAddressList = new CellRangeAddressList(rowId,rowId,1,1);
            DataValidation cacse = dvHelper.createValidation(formulaList, rangeAddressList);
            cacse.createErrorBox("error", "请选择正确的市");
            cacse.setShowErrorBox(true);
            cacse.setSuppressDropDownArrow(true);
            sheet1.addValidationData(cacse);

            // 区规则
            formulaList = dvHelper.createFormulaListConstraint("INDIRECT(B" + (rowId + 1) + ")");
            rangeAddressList = new CellRangeAddressList(rowId,rowId,2,2);
            cacse = dvHelper.createValidation(formulaList, rangeAddressList);
            cacse.createErrorBox("error", "请选择正确的区");
            cacse.setEmptyCellAllowed(true);
            cacse.setShowErrorBox(true);
            cacse.setSuppressDropDownArrow(true);
            sheet1.addValidationData(cacse);

            // 街道规则
            if (includeStreet){
                formulaList = dvHelper.createFormulaListConstraint("INDIRECT(C" + (rowId + 1) + ")");
                rangeAddressList = new CellRangeAddressList(rowId,rowId,3,3);
                cacse = dvHelper.createValidation(formulaList, rangeAddressList);
                cacse.createErrorBox("error", "请选择正确的街道");
                cacse.setEmptyCellAllowed(true);
                cacse.setShowErrorBox(true);
                cacse.setSuppressDropDownArrow(true);
                sheet1.addValidationData(cacse);
            }

            rowId++;
        }

        // 街道信息
        JSONArray streetData = new JSONArray();
        if (includeStreet){
            streetData = ExcelTool.getStreetData();
        }

//		int rowId2 = 450;
        for (int i = 0; i < streetData.size(); i++) {
            JSONObject jsonobs = new JSONObject().parseObject(streetData.get(i).toString());
            Map<String, Object> innerMap = jsonobs.getInnerMap();
            Set<String> keys = jsonobs.keySet();
            //遍历，通过迭代器
            Iterator<String> it = keys.iterator();
            while(it.hasNext())
            {
                String key = it.next();
                JSONArray o = (JSONArray) jsonobs.get(key);

                Row row = hideSheet.createRow(rowId);
                row.createCell(0).setCellValue(key);

                for (int j = 0; j < o.size(); j++) {
                    String value = o.get(j).toString();
                    Cell cell = row.createCell(j + 1);
                    cell.setCellValue(value);
                }

                try {
//						throw new IllegalArgumentException("Threw an IllegalArgumentException");
                    // 添加名称管理器
                    String range = ExcelTool.getRange(1, rowId + 1, o.size());
                    Name name = book.createName();
                    name.setNameName(key);
                    String formula = "site!" + range;
                    name.setRefersToFormula(formula);

                    // 添加有效性规则
                    // 市以规则，此处仅作一个示例
                    // "INDIRECT($A$" + 2 + ")" 表示规则数据会从名称管理器中获取key与单元格 A2 值相同的数据，如果A2是浙江省，那么此处就是 浙江省下的区域信息。
                    DataValidationConstraint formulaList = dvHelper.createFormulaListConstraint("INDIRECT(A" + (rowId + 1) + ")");
                    CellRangeAddressList rangeAddressList = new CellRangeAddressList(rowId,rowId,1,1);
                    DataValidation cacse = dvHelper.createValidation(formulaList, rangeAddressList);
                    cacse.createErrorBox("error", "请选择正确的市");
                    cacse.setShowErrorBox(true);
                    cacse.setSuppressDropDownArrow(true);
                    sheet1.addValidationData(cacse);

                    // 区规则
                    formulaList = dvHelper.createFormulaListConstraint("INDIRECT(B" + (rowId + 1) + ")");
                    rangeAddressList = new CellRangeAddressList(rowId,rowId,2,2);
                    cacse = dvHelper.createValidation(formulaList, rangeAddressList);
                    cacse.createErrorBox("error", "请选择正确的区");
                    cacse.setEmptyCellAllowed(true);
                    cacse.setShowErrorBox(true);
                    cacse.setSuppressDropDownArrow(true);
                    sheet1.addValidationData(cacse);

                    // 街道规则
                    if (includeStreet){
                        formulaList = dvHelper.createFormulaListConstraint("INDIRECT(C" + (rowId + 1) + ")");
                        rangeAddressList = new CellRangeAddressList(rowId,rowId,3,3);
                        cacse = dvHelper.createValidation(formulaList, rangeAddressList);
                        cacse.createErrorBox("error", "请选择正确的街道");
                        cacse.setEmptyCellAllowed(true);
                        cacse.setShowErrorBox(true);
                        cacse.setSuppressDropDownArrow(true);
                        sheet1.addValidationData(cacse);
                    }

                    rowId++;
                } catch(IllegalArgumentException e) {
                    System.out.println("Caught an IllegalArgumentException..." +  e.getMessage());
                }

            }
        }

        //导出数据
        try {
            //设置Http响应头告诉浏览器下载这个附件
            String filePath = fileName + ".xlsx";
            File dbfFile = new File(filePath);
            fileName = new String(filePath.getBytes(), "ISO-8859-1");
            response.setHeader("Content-Disposition", "attachment;Filename=" + fileName);
            OutputStream outputStream = response.getOutputStream();
            book.write(outputStream);

            outputStream.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("导出Excel出现严重异常，异常信息：" + ex.getMessage());
        }
    }

    public void exportErrorThirdUser(List<ThirdUserDto> list, HttpServletResponse httpServletResponse) {
        List<ThirdUserImportModule> userImportModuleList = new ArrayList<>();
        list.parallelStream().forEach(
                userDto -> {
                    ThirdUserImportModule userImportModule = new ThirdUserImportModule();
                    userImportModule.setName(userDto.getName());
                    userImportModule.setSex(userDto.getSex());
                    userImportModule.setKey(userDto.getKey());
                    userImportModule.setAgencyName(userDto.getAgencyName());
                    userImportModule.setResidentialName(userDto.getResidentialname());
                    userImportModule.setHouseInfo(userDto.getHouseInfo());
                    userImportModule.setImageName(userDto.getImageName());
                    userImportModule.setIdcard(userDto.getIdcard());
                    userImportModule.setTel(userDto.getTel());

                    userImportModule.setImportErrorMsg(userDto.getImportErrorMsg());
                    userImportModuleList.add(userImportModule);
                }
        );

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        writeExcel(httpServletResponse, userImportModuleList, "第三方住户导入错误记录" + sdf.format(new Date()), null, new ThirdUserImportModule());
    }
}
