package com.cool.store.service.visit.impl;

import cn.hutool.core.collection.CollStreamUtil;
import com.cool.store.constants.CommonConstants;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dao.*;
import com.cool.store.dao.ad.AdDistrictDAO;
import com.cool.store.dao.store.StoreMasterSignerInfoDAO;
import com.cool.store.dao.visit.VisitRecordDAO;
import com.cool.store.dto.region.BigRegionDTO;
import com.cool.store.entity.LineInfoDO;
import com.cool.store.entity.QualificationsInfoDO;
import com.cool.store.entity.RegionDO;
import com.cool.store.entity.StoreDO;
import com.cool.store.entity.store.StoreMasterSignerInfoDO;
import com.cool.store.entity.visit.VisitRecordDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.RocketMqTagEnum;
import com.cool.store.enums.visit.VisitStatusEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.mq.producer.SimpleMessageService;
import com.cool.store.request.visit.*;
import com.cool.store.service.SysRoleService;
import com.cool.store.service.UserAuthMappingService;
import com.cool.store.service.dict.impl.DictService;
import com.cool.store.service.visit.VisitRecordService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.poi.StringUtils;
import com.cool.store.vo.visit.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 拜访记录服务实现类
 * </p>
 *
 * @author wangff
 * @since 2025/12/8
 */
@Service
@RequiredArgsConstructor
public class VisitRecordServiceImpl implements VisitRecordService {
    private final VisitRecordDAO visitRecordDAO;
    private final UserAuthMappingService userAuthMappingService;
    private final QualificationsInfoDAO qualificationsInfoDAO;
    private final StoreDao storeDao;
    private final StoreMasterSignerInfoDAO storeSignerDAO;
    private final LineInfoDAO lineInfoDAO;
    private final BigRegionDAO bigRegionDAO;
    private final DictService dictService;
    private final SysRoleService sysRoleService;
    private final SimpleMessageService simpleMessageService;
    private final AdDistrictDAO adDistrictDAO;
    private final EnterpriseUserDAO enterpriseUserDAO;
    private final RegionDao regionDao;

    @Override
    public String signIn(VisitSignInRequest request) {
        VisitRecordDO record = VisitRecordDO.builder()
                .visitNo(generateVisitNo())
                .lineId(request.getLineId())
                .signInLonLat(request.getSignInLonLat())
                .signInAddress(request.getSignInAddress())
                .status(VisitStatusEnum.N_SIGN_OUT.getStatus())
                .signInTime(new Date())
                .userId(CurrentUserHolder.getUserId())
                .build();
        visitRecordDAO.insertSelective(record);
        simpleMessageService.send(String.valueOf(record.getId()), RocketMqTagEnum.VISIT_RECORD_INVALID, System.currentTimeMillis() + 12 * 60 * 60 * 1000);
        return record.getId().toString();
    }

    @Override
    public String signOut(VisitSignOutRequest request) {
        VisitRecordDO old = visitRecordDAO.getById(request.getId());
        verify(old);
        if (CommonConstants.INDEX_ZERO.equals(old.getCompleteEdit())) {
            throw new ServiceException(ErrorCodeEnum.VISIT_RECORD_NOT_COMPLETE_EDIT);
        }
        VisitRecordDO record = VisitRecordDO.builder()
                .id(request.getId())
                .signOutTime(new Date())
                .signOutLonLat(request.getSignOutLonLat())
                .signOutAddress(request.getSignOutAddress())
                .status(VisitStatusEnum.COMPLETE.getStatus())
                .build();
        visitRecordDAO.updateSelective(record);
        return record.getId().toString();
    }

    @Override
    public Boolean editRecord(VisitEditRequest request) {
        VisitRecordDO old = visitRecordDAO.getById(request.getId());
        verify(old);
        VisitRecordDO record = BeanUtil.toBean(request, VisitRecordDO.class);
        record.setCompleteEdit(CommonConstants.INDEX_ONE);
        return visitRecordDAO.updateSelective(record);
    }

    @Override
    public PageInfo<VisitPartnerListVO> visitPartnerList(VisitPartnerQueryRequest request) {
        List<Long> authRegionIds = null;
        String currentUserId = CurrentUserHolder.getUserId();
        if (!sysRoleService.checkIsAdmin(currentUserId) && !Boolean.TRUE.equals(request.getFilterAuth())) {
            authRegionIds = userAuthMappingService.getAuthRegionIdAndSubRegionIdExcludeStoreByUserId(currentUserId)
                    .stream()
                    .map(Long::valueOf)
                    .collect(Collectors.toList());
            List<BigRegionDTO> bigRegionList = bigRegionDAO.queryAllBigRegion(null, null, null);
            Set<Long> bigRegionIds = CollStreamUtil.toSet(bigRegionList, BigRegionDTO::getRegionId);
            authRegionIds.retainAll(bigRegionIds);
            if (CollectionUtils.isEmpty(authRegionIds)) {
                return new PageInfo<>();
            }
        }
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<Long> lineIds = visitRecordDAO.getPartnerLineId(authRegionIds, request.getKeyword(), request.getUserId());
        PageInfo<Long> page = new PageInfo<>(lineIds);
        List<VisitPartnerListVO> list = visitRecordDAO.getVisitRecordListByLineIds(lineIds, request.getUserId());
        PageInfo<VisitPartnerListVO> result = BeanUtil.toPage(page, VisitPartnerListVO.class);
        result.setList(list);

        List<LineInfoDO> lineList = lineInfoDAO.getByLineIds(lineIds);
        Map<Long, LineInfoDO> lineMap = CollStreamUtil.toMap(lineList, LineInfoDO::getId, v -> v);
        Map<Long, Integer> storeNumMap = getStoreNumMap(lineIds);
        Set<String> investmentManagerIds = CollStreamUtil.toSet(lineList, LineInfoDO::getInvestmentManager);
        Set<Long> investRegionIds = CollStreamUtil.toSet(lineList, LineInfoDO::getInvestRegionId);
        Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(new ArrayList<>(investmentManagerIds));
        Map<Long, String> regionNameMap = regionDao.getRegionNameMap(new ArrayList<>(investRegionIds));

        list.forEach(v -> {
            v.setOpenNum(storeNumMap.getOrDefault(v.getLineId(), 0));
            v.setIsVeteran(v.getOpenNum() > 0 ? 1 : 0);
            LineInfoDO lineInfoDO = lineMap.get(v.getLineId());
            if (Objects.nonNull(lineInfoDO)) {
                v.setName(lineInfoDO.getUsername());
                v.setMobile(lineInfoDO.getMobile());
                v.setInvestmentManagerName(userNameMap.get(lineInfoDO.getInvestmentManager()));
                v.setInvestRegionName(regionNameMap.get(lineInfoDO.getInvestRegionId()));
            }
        });
        return result;
    }

    private Map<Long, Integer> getStoreNumMap(List<Long> lineIds) {
        List<QualificationsInfoDO> qualificationList = qualificationsInfoDAO.getByLineIds(lineIds);
        Map<Long, String> idCardMap = CollStreamUtil.toMap(qualificationList, QualificationsInfoDO::getLineId, QualificationsInfoDO::getIdCardNo);
        // 根据身份证查询对应签约人开店数量
        List<StoreMasterSignerInfoDO> storeSignerList = storeSignerDAO.getListByIdCard(idCardMap.values());
        List<String> storeIds = CollStreamUtil.toList(storeSignerList, StoreMasterSignerInfoDO::getStoreId);
        List<StoreDO> effectiveStoreList = storeDao.getEffectiveStoreByStoreIds(storeIds);
        Set<String> effectiveStoreIds = CollStreamUtil.toSet(effectiveStoreList, StoreDO::getStoreId);

        Map<String, Integer> storeNumMap = new HashMap<>();
        for (StoreMasterSignerInfoDO signerInfoDO : storeSignerList) {
            if (effectiveStoreIds.contains(signerInfoDO.getStoreId())) {
                storeNumMap.compute(signerInfoDO.getSigner1IdCardNo(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
                storeNumMap.compute(signerInfoDO.getSigner2IdCardNo(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
            }
        }
        storeNumMap.remove(null);
        return CollStreamUtil.toMap(lineIds, v -> v, v -> storeNumMap.getOrDefault(idCardMap.get(v), 0));
    }

    @Override
    public PageInfo<VisitRecordSimpleListVO> recordSimpleList(VisitRecordSimpleQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<VisitRecordDO> list = visitRecordDAO.getByLineId(request.getLineId(), request.getVisitStartDate(), request.getVisitEndDate(), request.getUserId());
        PageInfo<VisitRecordDO> page = new PageInfo<>(list);
        Set<Long> lineIds = CollStreamUtil.toSet(list, VisitRecordDO::getLineId);
        Set<String> userIdList = CollStreamUtil.toSet(list, VisitRecordDO::getUserId);
        Map<String, String> userNameMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(userIdList)){
            userNameMap = enterpriseUserDAO.getUserNameMap(new ArrayList<>(userIdList));
        }
        List<LineInfoDO> lineList = lineInfoDAO.getByLineIds(new ArrayList<>(lineIds));
        Map<Long, LineInfoDO> lineMap = CollStreamUtil.toMap(lineList, LineInfoDO::getId, v -> v);
        PageInfo<VisitRecordSimpleListVO> result = BeanUtil.toPage(page, VisitRecordSimpleListVO.class);
        Map<String, String> finalUserNameMap = userNameMap;
        result.getList().forEach(v -> {
            LineInfoDO lineInfoDO = lineMap.get(v.getLineId());
            String userName = finalUserNameMap.getOrDefault(v.getUserId(), "");
            v.setUserName(userName);
            if (Objects.nonNull(lineInfoDO)) {
                v.setName(lineInfoDO.getUsername());
                v.setMobile(lineInfoDO.getMobile());
            }
        });
        return result;
    }

    @Override
    public VisitRecordDetailVO getDetail(Long id) {
        VisitRecordDO record = visitRecordDAO.getById(id);
        if (Objects.isNull(record)) {
            throw new ServiceException(ErrorCodeEnum.VISIT_RECORD_NOT_EXIST);
        }
        VisitRecordDetailVO vo = BeanUtil.toBean(record, VisitRecordDetailVO.class);
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(record.getLineId());
        if (Objects.nonNull(lineInfo)) {
            vo.setName(lineInfo.getUsername());
            vo.setMobile(lineInfo.getMobile());
            vo.setInvestmentManagerName(enterpriseUserDAO.getUserName(lineInfo.getInvestmentManager()));
            RegionDO investRegion = regionDao.getRegionById(lineInfo.getInvestRegionId());
            if (Objects.nonNull(investRegion)) {
                vo.setInvestRegionName(investRegion.getName());
            }
        }
        if (StringUtils.isNotBlank(record.getUserId())){
            String userName = enterpriseUserDAO.getUserName(record.getUserId());
            vo.setUserId(record.getUserId());
            vo.setUserName(userName);
        }
        Map<Long, Integer> storeNumMap = getStoreNumMap(Collections.singletonList(record.getLineId()));
        vo.setOpenNum(storeNumMap.getOrDefault(record.getLineId(), 0));
        vo.setIsVeteran(storeNumMap.getOrDefault(record.getLineId(), 0) > 0 ? 1 : 0);
        List<VisitPartnerListVO> list = visitRecordDAO.getVisitRecordListByLineIds(Collections.singletonList(record.getLineId()), null);
        Map<String, String> adNameMap = adDistrictDAO.getNameByCodes(Arrays.asList(vo.getDesireCity(), vo.getDesireDistrict()));
        if (CollectionUtils.isNotEmpty(list)) {
            VisitPartnerListVO partner = list.get(0);
            vo.setVisitNum(partner.getVisitNum());
            vo.setDesireCityName(adNameMap.get(vo.getDesireCity()));
            vo.setDesireDistrictName(adNameMap.get(vo.getDesireDistrict()));
        }
        dictService.fillDictField(vo);
        return vo;
    }

    @Override
    public Boolean cancelVisit(VisitCancelRequest request) {
        return visitRecordDAO.deleteById(request.getId());
    }

    @Override
    public PageInfo<VisitRecordListVO> recordList(VisitRecordQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<VisitRecordListVO> list = visitRecordDAO.getVisitRecordList(request);
        PageInfo<VisitRecordListVO> page = new PageInfo<>(list);
        Set<Long> lineIds = CollStreamUtil.toSet(list, VisitRecordListVO::getLineId);
        Set<String> userIdList = list.stream()
                .flatMap(v -> Stream.of(v.getVisitUserId(), v.getInvestmentManager()))
                .collect(Collectors.toSet());
        Set<Long> regionIds = CollStreamUtil.toSet(list, VisitRecordListVO::getInvestRegionId);
        Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(new ArrayList<>(userIdList));
        Map<Long, String> regionNameMap = regionDao.getRegionNameMap(new ArrayList<>(regionIds));
        List<String> adCodes = list.stream()
                .flatMap(v -> Stream.of(v.getDesireCity(), v.getDesireDistrict()))
                .distinct()
                .collect(Collectors.toList());
        Map<String, String> adNameMap = adDistrictDAO.getNameByCodes(adCodes);
        Map<Long, Integer> storeNumMap = getStoreNumMap(new ArrayList<>(lineIds));
        list.forEach(v -> {
            v.setIsVeteran(storeNumMap.getOrDefault(v.getLineId(), 0) > 0 ? 1 : 0);
            v.setDesireCityName(adNameMap.get(v.getDesireCity()));
            v.setDesireDistrictName(adNameMap.get(v.getDesireDistrict()));
            v.setVisitUserName(userNameMap.get(v.getVisitUserId()));
            v.setInvestRegionName(regionNameMap.get(v.getInvestRegionId()));
            v.setInvestmentManagerName(userNameMap.get(v.getInvestmentManager()));
        });
        dictService.fillDictField(list);
        return page;
    }

    @Override
    public void recordInvalid(Long id) {
        VisitRecordDO record = visitRecordDAO.getById(id);
        if (Objects.nonNull(record) && VisitStatusEnum.N_SIGN_OUT.getStatus().equals(record.getStatus())) {
            VisitRecordDO update = VisitRecordDO.builder().id(record.getId()).status(VisitStatusEnum.INVALID.getStatus()).build();
            visitRecordDAO.updateSelective(update);
        }
    }

    @Override
    public VisitRecordStatusStatisticsVO countStatusStatistics(VisitRecordQueryRequest request) {
        return visitRecordDAO.countStatusStatistics(request);
    }

    /**
     * 校验操作权限及拜访状态
     */
    private void verify(VisitRecordDO record) {
        if (Objects.isNull(record)) {
            throw new ServiceException(ErrorCodeEnum.VISIT_RECORD_NOT_EXIST);
        }
        if (VisitStatusEnum.INVALID.getStatus().equals(record.getStatus())) {
            throw new ServiceException(ErrorCodeEnum.VISIT_RECORD_INVALID);
        }
        if (VisitStatusEnum.COMPLETE.getStatus().equals(record.getStatus())) {
            throw new ServiceException(ErrorCodeEnum.VISIT_RECORD_COMPLETE);
        }
        if (!record.getUserId().equals(CurrentUserHolder.getUserId())) {
            throw new ServiceException(ErrorCodeEnum.VISIT_RECORD_NOT_YOUR_OWN);
        }
    }

    private String generateVisitNo() {
        return "V" + System.currentTimeMillis();
    }
}
