package com.xinelu.applet.service.nearbynursingstation.impl;

import com.xinelu.applet.dto.nursestation.NurseStationAppletDTO;
import com.xinelu.applet.mapper.nearbynursingstation.NearbyNursingStationMapper;
import com.xinelu.applet.service.nearbynursingstation.INearbyNursingStationService;
import com.xinelu.applet.vo.goodinfo.GoodInfoAndItemVO;
import com.xinelu.applet.vo.nearbynursingstation.InformationCategoryVO;
import com.xinelu.applet.vo.nearbynursingstation.NearbyNursingStationVO;
import com.xinelu.applet.vo.nearbynursingstation.NursingStationAndClassifyVO;
import com.xinelu.applet.vo.nearbynursingstation.PoserInfoHomeVO;
import com.xinelu.applet.vo.nurseclassifyinfo.NurseClassifyInfoList;
import com.xinelu.applet.vo.nurseclassifyinfo.NurseClassifyInfoVO;
import com.xinelu.applet.vo.specialdisease.StationClassifyInfoVO;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.page.TableDataInfo;
import com.xinelu.common.enums.NurseClassifyInfoEnum;
import com.xinelu.common.enums.NurseStationItemShelfStatusEnum;
import com.xinelu.common.enums.PoserModuleTypeEnum;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.PageServiceUtil;
import com.xinelu.manage.domain.nurseclassifyinfo.NurseClassifyInfo;
import com.xinelu.system.domain.SysConfig;
import com.xinelu.system.mapper.SysConfigMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ljh
 * @version 1.0
 * Create by 2022/9/2 12:37
 * 附近护理站信息
 */
@Service
public class NearbyNursingStationServiceImpl implements INearbyNursingStationService {

    @Resource
    private NearbyNursingStationMapper nearbyNursingStationMapper;
    @Resource
    private PageServiceUtil pageServiceUtil;
    @Resource
    private SysConfigMapper sysConfigMapper;

    /**
     * 距离用地球半径
     */
    private static final double EARTH_RADIUS = 6378.137;

    /**
     * 营业状态：营业中
     */
    private static final String OPEN_FOR_BUSINESS = "营业中";

    /**
     * 营业状态：休息中
     */
    private static final String SUSPENSION_OF_BUSINESS = "休息中";

    /**
     * 查询附近的护理站集合
     *
     * @param dto 搜索参数
     * @return com.xinyilu.common.core.domain.AjaxResult
     **/
    @Override
    public TableDataInfo getNearbyNursingStationInfoList(NurseStationAppletDTO dto) {
        // 查询附近护理站的信息集合
        pageServiceUtil.startPage();
        List<NursingStationAndClassifyVO> nearbyNursingStationList = nearbyNursingStationMapper.selectNursingStationIntroductionList(dto);
        //获取所有护理站id集合
        List<Long> stationIdIdList = nearbyNursingStationList.stream().filter(item -> Objects.nonNull(item.getNurseStationId())).map(NursingStationAndClassifyVO::getNurseStationId).distinct().collect(Collectors.toList());
        //查询所有的分类信息
        Map<Long, List<StationClassifyInfoVO>> stationClassifyMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(stationIdIdList)) {
            stationClassifyMap = nearbyNursingStationMapper.getStationClassifyInfoList(stationIdIdList).stream().filter(item -> Objects.nonNull(item.getNurseStationId())).collect(Collectors.groupingBy(StationClassifyInfoVO::getNurseStationId));
        }
        for (NursingStationAndClassifyVO nearbyNursingStationVO : nearbyNursingStationList) {
            if (StringUtils.isBlank(nearbyNursingStationVO.getLatitude()) || StringUtils.isBlank(nearbyNursingStationVO.getLongitude())) {
                nearbyNursingStationVO.setDistance(null);
            } else {
                String latitude = nearbyNursingStationVO.getLatitude();
                String longitude = nearbyNursingStationVO.getLongitude();
                double latitudeDouble = Double.parseDouble(latitude);
                double longitudeDouble = Double.parseDouble(longitude);
                double homeLongitudeDouble = Double.parseDouble(StringUtils.isBlank(dto.getHomeLongitude()) ? "0" : dto.getHomeLongitude());
                double homeLatitudeDouble = Double.parseDouble(StringUtils.isBlank(dto.getHomeLatitude()) ? "0" : dto.getHomeLatitude());
                double distance = getDistance(latitudeDouble, longitudeDouble, homeLatitudeDouble, homeLongitudeDouble);
                String valueOf = String.valueOf(distance);
                nearbyNursingStationVO.setDistance(valueOf);
            }
            if (!stationClassifyMap.isEmpty()) {
                nearbyNursingStationVO.setClassifyInfoList(stationClassifyMap.getOrDefault(nearbyNursingStationVO.getNurseStationId(), Lists.newArrayList()));
            }
        }
        return pageServiceUtil.getDataTable(nearbyNursingStationList);
    }

    /**
     * 查询护理项目分类信息列表
     *
     * @param nurseClassifyInfo 护理机构和护理项目分类信息
     * @return 护理机构和护理项目分类信息集合
     */
    @Override
    public NurseClassifyInfoVO getNurseClassifyList(NurseClassifyInfoVO nurseClassifyInfo) {
        NurseClassifyInfoVO nurseClassifyInfoVO = new NurseClassifyInfoVO();
        //查询护理站分类和护理项目分类集合信息
        List<String> typeList = Arrays.asList(NurseClassifyInfoEnum.NURSE_ITEM.getInfo(), NurseClassifyInfoEnum.NURSE_AGENCY.getInfo());
        NurseClassifyInfoList classifyInfo = new NurseClassifyInfoList();
        classifyInfo.setTypeList(typeList);
        List<NurseClassifyInfoList> classifyList = nearbyNursingStationMapper.getNurseClassifyList(classifyInfo);
        if (CollectionUtils.isNotEmpty(classifyList)) {
            List<NurseClassifyInfoList> itemClassifyInfoList = classifyList.stream().filter(item -> StringUtils.isNotBlank(item.getClassifyType()) && NurseClassifyInfoEnum.NURSE_ITEM.getInfo().equals(item.getClassifyType())).collect(Collectors.toList());
            List<NurseClassifyInfoList> agencyClassifyInfoList = classifyList.stream().filter(item -> StringUtils.isNotBlank(item.getClassifyType()) && NurseClassifyInfoEnum.NURSE_AGENCY.getInfo().equals(item.getClassifyType())).collect(Collectors.toList());
            nurseClassifyInfoVO.setNurseItemClassifyInfoList(itemClassifyInfoList);
            nurseClassifyInfoVO.setNurseAgencyClassifyInfoList(agencyClassifyInfoList);
        } else {
            nurseClassifyInfoVO.setNurseItemClassifyInfoList(Lists.newArrayList());
            nurseClassifyInfoVO.setNurseAgencyClassifyInfoList(Lists.newArrayList());
        }
        //海报信息集合
        PoserInfoHomeVO poserInfo = new PoserInfoHomeVO();
        poserInfo.setModuleType(StringUtils.isBlank(nurseClassifyInfo.getModuleType()) ? "" : nurseClassifyInfo.getModuleType());
        List<PoserInfoHomeVO> homePagePoserInfoList = nearbyNursingStationMapper.getHomePagePoserInfoList(poserInfo);
        nurseClassifyInfoVO.setPoserInfoList(homePagePoserInfoList);
        return nurseClassifyInfoVO;
    }

    /**
     * 获取附近某个护理站详细信息对象
     *
     * @param nurseStationId 护理站id
     * @param homeLongitude  经度
     * @param homeLatitude   维度
     * @return com.xinyilu.common.core.domain.AjaxResult
     */
    @Override
    public AjaxResult selectNursingStationIntroductionList(Long nurseStationId, String homeLongitude, String homeLatitude) {
        //获取附近护理站以及护理站标签信息集合
        NearbyNursingStationVO nearbyNursingStationVO = nearbyNursingStationMapper.selectNursingStationIntroductionListTwo(nurseStationId);
        //筛选海报模块标识，护理机构模块：NURSE_AGENCY_MODULE
        List<PoserInfoHomeVO> stationPoserInfoList = nearbyNursingStationVO.getPoserInfoList().stream().filter(Objects::nonNull).filter(item -> StringUtils.isNotBlank(item.getModuleType()) && item.getModuleType().equals(PoserModuleTypeEnum.NURSE_AGENCY_MODULE.getInfo())).collect(Collectors.toList());
        nearbyNursingStationVO.setPoserInfoList(stationPoserInfoList);
        //获取配置系统配置中的参数信息
        List<String> keyList = Arrays.asList("MORNING_START_TIME", "MORNING_END_TIME", "AFTERNOON_START_TIME", "AFTERNOON_END_TIME");
        Map<String, String> keysMap = sysConfigMapper.getSystemConfigByKeys(keyList).stream()
                .filter(item -> StringUtils.isNotBlank(item.getConfigKey()) && StringUtils.isNotBlank(item.getConfigValue()))
                .collect(Collectors.toMap(SysConfig::getConfigKey, SysConfig::getConfigValue));
        if (keysMap.isEmpty()) {
            keysMap.put("MORNING_START_TIME", "08:00:00");
            keysMap.put("MORNING_END_TIME", "12:00:00");
            keysMap.put("AFTERNOON_START_TIME", "13:30:00");
            keysMap.put("AFTERNOON_END_TIME", "18:00:00");
        }
        //如果系统护理站没有设置营业时间，那么就默赋值系统默认的营业时间
        if (Objects.isNull(nearbyNursingStationVO.getMorningOpenStartTime())) {
            nearbyNursingStationVO.setMorningOpenStartTime(LocalTime.parse(keysMap.get("MORNING_START_TIME")));
        }
        if (Objects.isNull(nearbyNursingStationVO.getMorningOpenEndTime())) {
            nearbyNursingStationVO.setMorningOpenEndTime(LocalTime.parse(keysMap.get("MORNING_END_TIME")));
        }
        if (Objects.isNull(nearbyNursingStationVO.getAfternoonOpenStartTime())) {
            nearbyNursingStationVO.setAfternoonOpenStartTime(LocalTime.parse(keysMap.get("AFTERNOON_START_TIME")));
        }
        if (Objects.isNull(nearbyNursingStationVO.getAfternoonOpenEndTime())) {
            nearbyNursingStationVO.setAfternoonOpenEndTime(LocalTime.parse(keysMap.get("AFTERNOON_END_TIME")));
        }
        //设置营业时间和营业状态
        this.setBusinessTime(nearbyNursingStationVO, LocalTime.now());
        //查询护理项目分类
        List<NurseClassifyInfo> nurseClassifyInfoList = nearbyNursingStationMapper.selectNurseClassifyByClassifyType(NurseClassifyInfoEnum.NURSE_ITEM.getInfo());
        nearbyNursingStationVO.setNurseClassifyInfoList(nurseClassifyInfoList);
        //计算经纬度
        if (StringUtils.isBlank(nearbyNursingStationVO.getLatitude()) || StringUtils.isBlank(nearbyNursingStationVO.getLongitude())) {
            nearbyNursingStationVO.setDistance(null);
        } else {
            String latitude = nearbyNursingStationVO.getLatitude();
            String longitude = nearbyNursingStationVO.getLongitude();
            double latitudeDouble = Double.parseDouble(latitude);
            double longitudeDouble = Double.parseDouble(longitude);
            double homeLongitudeDouble = Double.parseDouble(StringUtils.isBlank(homeLongitude) ? "0" : homeLongitude);
            double homeLatitudeDouble = Double.parseDouble(StringUtils.isBlank(homeLatitude) ? "0" : homeLatitude);
            double distance = getDistance(latitudeDouble, longitudeDouble, homeLatitudeDouble, homeLongitudeDouble);
            String valueOf = String.valueOf(distance);
            nearbyNursingStationVO.setDistance(valueOf);
        }
        return AjaxResult.success(nearbyNursingStationVO);
    }

    /**
     * 获取附近护理站服务信息对象
     *
     * @param nurseStationId      护理站id
     * @param nurseClassifyInfoId 护理项目所属分类id
     * @return GoodInfoAndItemVO
     */
    @Override
    public List<GoodInfoAndItemVO> selectNursingStationItemList(Long nurseStationId, Long nurseClassifyInfoId) {
        return nearbyNursingStationMapper.getNurseStationItemList(nurseStationId, nurseClassifyInfoId, NurseStationItemShelfStatusEnum.SHELF.getInfo());
    }

    /**
     * 获取附近护理站产品信息对象
     *
     * @param nurseStationId 护理站id
     * @return GoodInfoVO
     */
    @Override
    public List<GoodInfoAndItemVO> selectNursingStationProductList(Long nurseStationId) {
        return nearbyNursingStationMapper.getNurseGoodsList(nurseStationId);
    }

    /**
     * 分页查询健康常识列表信息
     *
     * @param informationCategoryType 资讯类型
     * @return com.xinyilu.common.core.domain.AjaxResult 分类显示信息
     */
    @Override
    public List<InformationCategoryVO> getHeathHousingList(String informationCategoryType) {
        if (StringUtils.isBlank(informationCategoryType)) {
            throw new ServiceException("资讯类型不能为空！");
        }
        return nearbyNursingStationMapper.getInformationCategoryList(informationCategoryType);
    }

    /**
     * 通过经纬度获取距离(单位：米)
     *
     * @param latitudeDouble      护理站经度
     * @param longitudeDouble     护理站纬度
     * @param homeLatitudeDouble  被护理人经度
     * @param homeLongitudeDouble 被护理人维度
     * @return 距离
     */
    public static double getDistance(double latitudeDouble, double longitudeDouble, double homeLatitudeDouble,
                                     double homeLongitudeDouble) {
        //经纬度计算
        double radLat = rad(latitudeDouble);
        double homeRadLat = rad(homeLatitudeDouble);
        double a = radLat - homeRadLat;
        double b = rad(longitudeDouble) - rad(homeLongitudeDouble);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
                + Math.cos(radLat) * Math.cos(homeRadLat) * Math.pow(Math.sin(b / 2), 2)));
        //地球半径
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        s = Double.parseDouble(String.format("%.2f", s));
        return s;
    }

    /**
     * 距离用pai
     *
     * @param d 数字
     * @return 数值
     */
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    /**
     * 设置时间
     *
     * @param nearbyNursingStationVO 信息
     */
    private void setBusinessTime(NearbyNursingStationVO nearbyNursingStationVO, LocalTime nowTime) {
        LocalTime morningOpenStartTime = nearbyNursingStationVO.getMorningOpenStartTime();
        LocalTime morningOpenEndTime = nearbyNursingStationVO.getMorningOpenEndTime();
        LocalTime afternoonOpenStartTime = nearbyNursingStationVO.getAfternoonOpenStartTime();
        LocalTime afternoonOpenEndTime = nearbyNursingStationVO.getAfternoonOpenEndTime();
        //获取当前时间判断是否营业状态
        if ((nowTime.isAfter(morningOpenStartTime) && nowTime.isBefore(morningOpenEndTime)) || (nowTime.isAfter(afternoonOpenStartTime) && nowTime.isBefore(afternoonOpenEndTime))) {
            nearbyNursingStationVO.setBusinessStatus(OPEN_FOR_BUSINESS);
        } else {
            nearbyNursingStationVO.setBusinessStatus(SUSPENSION_OF_BUSINESS);
        }
    }
}
