package com.yuchen.saas.park.service.service.property.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuchen.saas.integration.feign.api.util.PageConverterUtils;
import com.yuchen.saas.manage.dict.api.feign.IDictClient;
import com.yuchen.saas.park.api.dto.property.PropertyEnterpriseAddressListQueryDto;
import com.yuchen.saas.park.api.dto.property.PropertyHouseEnterpriseDto;
import com.yuchen.saas.park.api.dto.property.PropertyHouseEnterpriseQueryDto;
import com.yuchen.saas.park.api.entity.park.PmgBatParkInfo;
import com.yuchen.saas.park.api.entity.property.*;
import com.yuchen.saas.park.api.enums.property.*;
import com.yuchen.saas.park.api.vo.property.*;
import com.yuchen.saas.park.service.mapper.property.PropertyHouseEnterpriseMapper;
import com.yuchen.saas.park.service.service.PmgBatParkInfoService;
import com.yuchen.saas.park.service.service.property.*;
import com.yuchen.saas.park.service.service.property.bill.PropertyBillService;
import lombok.extern.slf4j.Slf4j;
import org.nest.springwrap.core.log.exception.ServiceException;
import org.nest.springwrap.core.mp.base.BaseServiceImpl;
import org.nest.springwrap.core.mp.support.NestPage;
import org.nest.springwrap.core.secure.ContextUser;
import org.nest.springwrap.core.secure.utils.AuthUtil;
import org.nest.springwrap.core.tool.utils.BeanUtil;
import org.nest.springwrap.core.tool.utils.Func;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author 蔡文强
 * @Date 2023/11/28 10:56
 * @Description 园区入驻企业表 服务实现类
 */
@Slf4j
@Service
public class PropertyHouseEnterpriseServiceImpl extends BaseServiceImpl<PropertyHouseEnterpriseMapper, PropertyHouseEnterprise> implements IPropertyHouseEnterpriseService {

    @Resource
    private PmgBatParkInfoService parkInfoService;
    @Resource
    private IPropertyCustomerArchivesService customerArchivesService;
    @Resource
    private IPropertyEnterpriseMemberService enterpriseMemberService;
    @Resource
    private IPropertyEnterpriseAddressService enterpriseAddressService;
    @Resource
    private PropertyHousesService housesService;
    @Resource
    private PropertyBillService propertyBillService;
    @Resource
    private IDictClient dictClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveorUpdateHouseEnterprise(PropertyHouseEnterpriseDto enterpriseDto) {
        PropertyHouseEnterprise enterprise = BeanUtil.copyProperties(enterpriseDto, PropertyHouseEnterprise.class);
        if (Func.isEmpty(enterpriseDto.getId())) {
            ContextUser contextUser = AuthUtil.getUser();
            if (Func.isEmpty(contextUser)) {
                throw new ServiceException("用户不存在");
            }
            Long registerPeopleId = contextUser.getUserDetailId();
            List<Long> houseIds = Func.toLongList(enterpriseDto.getHouseIds());
            for (Long houseId : houseIds) {
                enterprise.setId(null);
                enterprise.setHouseId(houseId);
                enterprise.setCreatePeopleId(registerPeopleId);
                enterprise.setCreateType(CreateTypeEnum.BACK_ADD.getValue());
                if (Func.isNotEmpty(enterprise.getStartDate()) && enterprise.getStartDate().after(new Date())) {
                    enterprise.setEntryStatus(EntryStatusEnum.NO_ENTRY.getValue());
                } else if (Func.isNotEmpty(enterprise.getStartDate()) && enterprise.getStartDate().before(new Date())) {
                    enterprise.setEntryStatus(EntryStatusEnum.ENTRY.getValue());
                } else if (Func.isNotEmpty(enterprise.getEndDate()) && enterprise.getEndDate().before(new Date())) {
                    enterprise.setEntryStatus(EntryStatusEnum.EXPIRED.getValue());
                } else {
                    enterprise.setEntryStatus(EntryStatusEnum.ENTRY.getValue());
                }
                save(enterprise);
            }
        } else {
            enterprise.setHouseId(Long.parseLong(enterpriseDto.getHouseIds()));
            updateById(enterprise);
        }
        //同步客户档案
        PropertyCustomerArchives customerArchives = customerArchivesService.getCustomerArchivesById(enterpriseDto.getCustomerArchivesId());
        customerArchives.setOrganType(enterpriseDto.getOrganType());
        customerArchives.setOrganIndustry(enterpriseDto.getOrganIndustry());
        customerArchives.setOrganScale(enterpriseDto.getOrganScale());
        customerArchives.setIdType(enterpriseDto.getIdType());
        customerArchives.setIdNo(enterpriseDto.getIdNo());
        customerArchives.setLinkManOne(enterpriseDto.getLinkMan());
        customerArchives.setLinkPhoneOne(enterpriseDto.getLinkPhone());
        customerArchives.setIsLink(YesOrNoEnum.YES.getValue());
        return customerArchivesService.updateById(customerArchives);
    }

    @Override
    public Boolean deleteHouseEnterprise(Long id) {
        List<PropertyBill> propertyBillList = propertyBillService.lambdaQuery().in(PropertyBill::getPayStatus, 1, 2, 3)
                .eq(PropertyBill::getCustomerId, id).list();
        if (Func.isNotEmpty(propertyBillList)) {
            throw new ServiceException("该企业有未结账单，不能移除");
        }
        LambdaQueryWrapper<PropertyEnterpriseMember> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(PropertyEnterpriseMember::getEnterpriseId, id);
        enterpriseMemberService.remove(queryWrapper);
        //todo 登记状态更新
        PropertyEnterpriseAddress enterpriseAddress = enterpriseAddressService.lambdaQuery().eq(PropertyEnterpriseAddress::getLinkId, id).one();
        if (Func.isNotEmpty(enterpriseAddress)) {
            enterpriseAddress.setIsValid(1);
            enterpriseAddressService.updateById(enterpriseAddress);
        }
        return removeById(id);
    }

    @Override
    public PropertyHouseEnterpriseVo getHouseEnterpriseById(Long id) {
        PropertyHouseEnterprise enterprise = getById(id);
        if (Func.isEmpty(enterprise)) {
            throw new ServiceException("入驻企业不存在");
        }
        PropertyHouseEnterpriseVo enterpriseVo = BeanUtil.copyProperties(enterprise, PropertyHouseEnterpriseVo.class);
        PropertyCustomerArchives customerArchives = customerArchivesService.getCustomerArchivesById(enterprise.getCustomerArchivesId());
        enterpriseVo.setEnterpriseName(customerArchives.getCustomerName());
        enterpriseVo.setOrganType(customerArchives.getOrganType());
        enterpriseVo.setOrganIndustry(customerArchives.getOrganIndustry());
        enterpriseVo.setOrganScale(customerArchives.getOrganScale());
        enterpriseVo.setIdType(customerArchives.getIdType());
        enterpriseVo.setIdNo(customerArchives.getIdNo());
        enterpriseVo.setHouseIds(String.valueOf(enterprise.getHouseId()));
        return enterpriseVo;
    }

    @Override
    public NestPage<PropertyHouseEnterpriseListVo> getHouseEnterprisePageList(PropertyHouseEnterpriseQueryDto queryDto) {
        if (Func.isNotEmpty(queryDto.getBuildingId()) && Func.isEmpty(queryDto.getHouseId())) {
            List<Long> houseIdList = housesService.listByBuildingId(queryDto.getBuildingId()).stream().map(PropertyHouses::getId).collect(Collectors.toList());
            queryDto.setHouseIdList(houseIdList);
        }
        // 分页获取数据
        Page<PropertyHouseEnterpriseListVo> page = new Page<>(queryDto.getCurrent(), queryDto.getSize());
        page = baseMapper.getHouseEnterprisePageList(page, queryDto);
        List<PropertyHouseEnterpriseListVo> list = page.getRecords();
        Map<Long, String> parkMap = getParkMap();
        for (PropertyHouseEnterpriseListVo vo : list) {
            Integer count = enterpriseMemberService.lambdaQuery().eq(PropertyEnterpriseMember::getEnterpriseId, vo.getId()).count();
            vo.setParkName(parkMap.get(vo.getParkId()));
            vo.setRegisterCount(count);
            PropertyHousesVo propertyHousesVo = housesService.getPropertyHousesDetail(vo.getHouseId());
            //拼接显示楼栋+单元+楼层+房间名称。
            vo.setAddress(propertyHousesVo.getBuildingName() + "-" + propertyHousesVo.getUnitNum() + "-" + propertyHousesVo.getFloorNum() + "-" + propertyHousesVo.getHouseName());
        }
        page.setRecords(list);
        return PageConverterUtils.convert(page);
    }

    @Override
    public PropertyHouseEnterpriseImportResVo importHouseEnterprise(MultipartFile file) {
        if (!(file.getOriginalFilename().endsWith(".xlsx") || file.getOriginalFilename().endsWith(".xls"))) {
            throw new ServiceException("请选择正确的excel文件");
        }
        PropertyHouseEnterpriseImportResVo vo = new PropertyHouseEnterpriseImportResVo();
        vo.setImportSize(0);
        vo.setFailSize(0);
        vo.setSuccessSize(0);
        List<String> msg = new ArrayList<>();
        vo.setMsg(msg);
        List<PmgBatParkInfo> list = parkInfoService.list();
        Map<String, PmgBatParkInfo> parkMap = list.stream().collect(Collectors.toMap(PmgBatParkInfo::getParkName, a -> a));
        try {
            EasyExcel.read(file.getInputStream(),
                    PropertyHouseEnterpriseImportExcelVo.class, new ReadListener() {

                        @Override
                        public void onException(Exception exception, AnalysisContext context) throws Exception {
                            log.error("导出异常", exception);
                            log.info("context", context);
                            vo.setFailSize(vo.getFailSize() + 1);
                            Integer rowIndex = context.readRowHolder().getRowIndex() - 1;
                            vo.getMsg().add(String.format("第%s条导入失败,失败原因:%s;", rowIndex, exception.getMessage()));
                        }

                        @Override
                        public void invokeHead(Map headMap, AnalysisContext context) {
                            log.info("context", context);
                            log.info("headMap", headMap);
                        }

                        @Override
                        public void invoke(Object o, AnalysisContext analysisContext) {
                            vo.setImportSize(vo.getImportSize() + 1);
                            PropertyHouseEnterpriseImportExcelVo importVo = (PropertyHouseEnterpriseImportExcelVo) o;
                            saveImport(importVo, parkMap);

                        }

                        @Override
                        public void extra(CellExtra extra, AnalysisContext context) {
                            log.info("extra", context);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                            log.info("analysisContext", analysisContext);
                        }

                        @Override
                        public boolean hasNext(AnalysisContext context) {
                            return true;
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            log.info("导入异常", e);
        }

        return vo;
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveImport(PropertyHouseEnterpriseImportExcelVo importVo, Map<String, PmgBatParkInfo> parkMap) {

        if (Func.isBlank(importVo.getParkName())){
            throw new ServiceException("园区不能为空");
        }
        if (Func.isBlank(importVo.getEnterpriseName())){
            throw new ServiceException("组织名称不能为空");
        }
        if (Func.isBlank(importVo.getOrganType())){
            throw new ServiceException("机构类型不能为空");
        }
        if (Func.isBlank(importVo.getOrganIndustry())){
            throw new ServiceException("所属行业不能为空");
        }
        if (Func.isBlank(importVo.getOrganScale())){
            throw new ServiceException("组织规模不能为空");
        }
        if (Func.isBlank(importVo.getIdTypeName())){
            throw new ServiceException("证件类型不能为空");
        }
        if (Func.isBlank(importVo.getIdNo())){
            throw new ServiceException("证件号码不能为空");
        }
        if (Func.isBlank(importVo.getLinkMan())){
            throw new ServiceException("联系人不能为空");
        }
        if (Func.isBlank(importVo.getLinkPhone())){
            throw new ServiceException("联系电话不能为空");
        }
        if (Func.isBlank(importVo.getSettleInTypeName())){
            throw new ServiceException("入驻类型不能为空");
        }
        if (Func.isBlank(importVo.getHouseCode())){
            throw new ServiceException("房源代码不能为空");
        }
        if (Func.isEmpty(importVo.getStartDate())){
            throw new ServiceException("入驻日期不能为空");
        }
        PropertyHouseEnterprise enterprise = new PropertyHouseEnterprise();
        BeanUtils.copyProperties(importVo,enterprise);

        String parkName = importVo.getParkName().replaceAll("\\s*", "");
        if (parkMap.containsKey(parkName)) {
            PmgBatParkInfo parkInfo = parkMap.get(parkName);
            enterprise.setParkId(parkInfo.getId());
        } else {
            throw new ServiceException("园区名称不存在");
        }

        List<PropertyHouses> list = housesService.list();
        Map<String, PropertyHouses> houseMap = list.stream().collect(Collectors.toMap(PropertyHouses::getResourceCode, a -> a));
        String houseCode = importVo.getHouseCode().replaceAll("\\s*", "");
        if (houseMap.containsKey(houseCode)) {
            PropertyHouses houses = houseMap.get(houseCode);
            enterprise.setHouseId(houses.getId());
        } else {
            throw new ServiceException("房间不存在");
        }
        Date startDate = importVo.getStartDate();
        Date endDate = importVo.getEndDate();
        if (startDate.after(new Date())) {
            enterprise.setEntryStatus(EntryStatusEnum.NO_ENTRY.getValue());
        } else if (startDate.before(new Date())) {
            enterprise.setEntryStatus(EntryStatusEnum.ENTRY.getValue());
        } else if (Func.isNotEmpty(endDate) && endDate.before(new Date())) {
            enterprise.setEntryStatus(EntryStatusEnum.EXPIRED.getValue());
        } else {
            enterprise.setEntryStatus(EntryStatusEnum.ENTRY.getValue());
        }
        //入驻类型
        String settleInTypeName = importVo.getSettleInTypeName().replaceAll("\\s*", "");
        if (settleInTypeName.equals("房源业主")) {
            enterprise.setSettleInType(1);
        } else if (settleInTypeName.equals("房源租客")) {
            enterprise.setSettleInType(2);
        } else {
            throw new ServiceException("入驻类型不存在");
        }

        enterprise.setCreateType(CreateTypeEnum.BACK_ADD.getValue());
        ContextUser contextUser = AuthUtil.getUser();
        if (Func.isEmpty(contextUser)) {
            throw new ServiceException("用户不存在");
        }
        enterprise.setCreatePeopleId(contextUser.getUserDetailId());

        //同步客户档案
        PropertyCustomerArchives customerArchives = customerArchivesService.lambdaQuery().eq(PropertyCustomerArchives::getCustomerType, CustomerTypeEnum.ORGAN.getValue())
                .eq(PropertyCustomerArchives::getIdNo, importVo.getIdNo()).one();
        if (Func.isNotEmpty(customerArchives)) {
            customerArchives.setOrganType(importVo.getOrganType());
            customerArchives.setOrganIndustry(importVo.getOrganIndustry());
            customerArchives.setOrganScale(importVo.getOrganScale());
            customerArchives.setIdType(1);
            customerArchives.setIdNo(importVo.getIdNo());
            customerArchives.setIsLink(YesOrNoEnum.YES.getValue());
            customerArchivesService.updateById(customerArchives);
            enterprise.setCustomerArchivesId(customerArchives.getId());
        } else {
            PropertyCustomerArchives add = new PropertyCustomerArchives();
            add.setParkId(enterprise.getParkId());
            add.setCustomerType(CustomerTypeEnum.ORGAN.getValue());
            add.setCustomerCategory(CustomerCategoryEnum.HOUSE_TENANT.getValue());
            add.setCustomerName(importVo.getEnterpriseName());
            add.setOrganType(importVo.getOrganType());
            add.setOrganIndustry(importVo.getOrganIndustry());
            add.setOrganScale(importVo.getOrganScale());
            add.setIdType(1);
            add.setIdNo(importVo.getIdNo());
            add.setCreateType(CreateTypeEnum.AUTO_SYNC.getValue());
            add.setCreatePeopleId(contextUser.getUserDetailId());
            add.setIsLink(YesOrNoEnum.YES.getValue());
            customerArchivesService.save(add);
            enterprise.setCustomerArchivesId(add.getId());
        }

        //判断企业是否存在
        LambdaQueryWrapper<PropertyHouseEnterprise> isExitQuery = Wrappers.lambdaQuery();
        isExitQuery.eq(PropertyHouseEnterprise::getParkId, enterprise.getParkId());
        isExitQuery.eq(PropertyHouseEnterprise::getCustomerArchivesId, enterprise.getCustomerArchivesId());
        isExitQuery.eq(PropertyHouseEnterprise::getHouseId, enterprise.getHouseId());
        PropertyHouseEnterprise isExit = this.getOne(isExitQuery);
        if (Func.isNotEmpty(isExit)) {
           removeById(isExit.getId());
        }
        this.save(enterprise);
    }


    @Override
    public void exportHouseEnterprise(PropertyHouseEnterpriseQueryDto queryDto, HttpServletResponse response) {
        List<PropertyHouseEnterpriseListVo> list = baseMapper.getHouseEnterpriseList(queryDto);
        List<PropertyHouseEnterpriseExcelVo> excelVoList = BeanUtil.copyProperties(list, PropertyHouseEnterpriseExcelVo.class);
        Map<Long, String> parkMap = getParkMap();
        excelVoList.forEach(excelVo -> {
            excelVo.setParkName(parkMap.get(excelVo.getParkId()));
            //机构类型
            String organType = dictClient.getValue("organ_type", excelVo.getOrganType()).getData();
            excelVo.setOrganType(organType);
            //所属行业
            String organIndustry = dictClient.getValue("company_trade", excelVo.getOrganIndustry()).getData();
            excelVo.setOrganIndustry(organIndustry);
            //证件类型
            excelVo.setIdTypeName(IdTypeEnum.getDescByCode(excelVo.getIdType()));
            //已登记成员
            Integer count = enterpriseMemberService.lambdaQuery().eq(PropertyEnterpriseMember::getEnterpriseId, excelVo.getId()).count();
            excelVo.setRegisterCount(count);
            PropertyHousesVo propertyHousesVo = housesService.getPropertyHousesDetail(excelVo.getHouseId());
            //拼接显示楼栋+单元+楼层+房间名称。
            excelVo.setAddress(propertyHousesVo.getBuildingName() + "-" + propertyHousesVo.getUnitNum() + "-" + propertyHousesVo.getFloorNum() + "-" + propertyHousesVo.getHouseName());
            //入驻状态
            excelVo.setEntryStatusName(EntryStatusEnum.getDescByCode(excelVo.getEntryStatus()));

        });
        try {
            String fileName = URLEncoder.encode("入驻企业表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), PropertyHouseEnterpriseExcelVo.class)
                    .sheet("入驻企业表")
                    .doWrite(excelVoList); //最终处理好的数据结果集list
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }

    }

    @Override
    public NestPage<PropertyEnterpriseAddressListVo> getEnterpriseAddressList(PropertyEnterpriseAddressListQueryDto queryDto) {
        return enterpriseAddressService.getEnterpriseAddressList(queryDto);
    }

    /**
     * @description 获取园区信息列表Map
     */
    private Map<Long, String> getParkMap() {
        List<PmgBatParkInfo> parkList = parkInfoService.getAllPark();
        return parkList.stream().collect(Collectors.toMap(PmgBatParkInfo::getId, PmgBatParkInfo::getParkName));
    }


}
