/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package com.unis.basic.info.modular.grainPriceCollect.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.unis.auth.core.util.StpClientUtil;
import com.unis.auth.core.util.StpLoginUserUtil;
import com.unis.auth.modular.login.entity.UserCollectLogin;
import com.unis.basic.info.modular.grainPriceCollect.entity.GrainPriceCollect;
import com.unis.basic.info.modular.grainPriceCollect.mapper.GrainPriceCollectMapper;
import com.unis.basic.info.modular.grainPriceCollect.param.GrainPriceCollectAddParam;
import com.unis.basic.info.modular.grainPriceCollect.param.GrainPriceCollectEditParam;
import com.unis.basic.info.modular.grainPriceCollect.param.GrainPriceCollectIdParam;
import com.unis.basic.info.modular.grainPriceCollect.param.GrainPriceCollectPageParam;
import com.unis.basic.info.modular.grainPriceCollect.service.GrainPriceCollectService;
import com.unis.basic.info.modular.grainPriceCollectCategory.entity.GrainPriceCollectCategory;
import com.unis.basic.info.modular.grainPriceCollectCategory.enums.GrainPriceCollectTypeEnum;
import com.unis.basic.info.modular.grainPriceCollectCategory.param.GrainPriceCollectCategoryAddParam;
import com.unis.basic.info.modular.grainPriceCollectCategory.param.GrainPriceCollectCategoryEditParam;
import com.unis.basic.info.modular.grainPriceCollectCategory.service.GrainPriceCollectCategoryService;
import com.unis.basic.info.modular.grainPriceCollectCitySum.entity.GrainPriceCollectCitySum;
import com.unis.basic.info.modular.grainPriceCollectCitySum.service.GrainPriceCollectCitySumService;
import com.unis.basic.info.modular.pricemonitor.entity.PriceMonitor;
import com.unis.basic.info.modular.pricemonitor.service.PriceMonitorService;
import com.unis.basic.info.modular.remindcycle.entity.RemindCycle;
import com.unis.basic.info.modular.remindcycle.service.RemindCycleService;
import com.unis.common.enums.CommonSortOrderEnum;
import com.unis.common.exception.CommonException;
import com.unis.common.geo.GeoPoint;
import com.unis.common.geo.GeoPointConverter;
import com.unis.common.page.CommonPageRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;

/**
 * 粮食价格采集Service接口实现类
 *
 * @author TS
 * @date  2024/04/03 10:44
 **/
@Service
public class GrainPriceCollectServiceImpl extends ServiceImpl<GrainPriceCollectMapper, GrainPriceCollect> implements GrainPriceCollectService {
    @Resource
    private  GrainPriceCollectMapper grainPriceCollectMapper;

    @Resource
    private PriceMonitorService priceMonitorService;

    @Resource
    private RemindCycleService remindCycleService;

    @Autowired
    private GrainPriceCollectCategoryService grainPriceCollectCategoryService;

    @Autowired
    private GrainPriceCollectCitySumService grainPriceCollectCitySumService;
    @Override
    public Page<GrainPriceCollect> page(GrainPriceCollectPageParam grainPriceCollectPageParam) {
        QueryWrapper<GrainPriceCollect> queryWrapper = new QueryWrapper<>();
        if(ObjectUtil.isAllNotEmpty(grainPriceCollectPageParam.getSortField(), grainPriceCollectPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(grainPriceCollectPageParam.getSortOrder());
            queryWrapper.orderBy(true, grainPriceCollectPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(grainPriceCollectPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(GrainPriceCollect::getId);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(GrainPriceCollectAddParam grainPriceCollectAddParam) {

        // 获取当前时间
        Date date  = new Date();
        GrainPriceCollect grainPriceCollect = BeanUtil.toBean(grainPriceCollectAddParam, GrainPriceCollect.class);
        List<RemindCycle>  remindCycles =   remindCycleService.list();
        //比较当天是不是报送日
        RemindCycle remindCycle = remindCycles.get(0);

        if (!isCurrentDateReportDay(date, remindCycle)) {
            throw new CommonException("当前不是报送日");
        }

        PriceMonitor priceMonitor = priceMonitorService.queryEntity(grainPriceCollectAddParam.getPriceMonitorId());
        if (priceMonitor == null) {
            System.out.println("未找到对应的PriceMonitor实体");
            throw new CommonException("未找到对应的监测点");
        }
        /*
            定位开关开启：需要实地采集 （判断采集范围）
            定位开关关闭：不是实地采集
         */
        int locationSwitch = priceMonitor.getLocationSwitch();
        if (locationSwitch == 0) { // 关闭
            grainPriceCollect.setIsSelfPriceMonitor(0);
        } else { // 开启
            try {
                String point = grainPriceCollectAddParam.getPoint();
                if (point != null) {
                    String[] coordinates = point.split(",");
                    if (coordinates.length < 2) {
                        System.out.println("无效的坐标数据");
                        throw new CommonException("无效的坐标数据");
                    }
                    double latitude = Double.parseDouble(coordinates[0].trim());
                    double longitude = Double.parseDouble(coordinates[1].trim());

                    GeoPoint siteLocation = priceMonitor.getGeoPoint();
                    GeoPoint currentLocation = new GeoPoint(latitude, longitude);

                    double distanceToSite = GeoPointConverter.calculateApproximateDistance(currentLocation, siteLocation);

                    if (distanceToSite > 100) {
                        System.out.println("差距大于100");
                        throw new CommonException("不在采集点范围内");
                    } else {
                        grainPriceCollect.setIsSelfPriceMonitor(1);
                    }
                } else {
                    throw new CommonException("请填写有效坐标");
                }
            } catch (NumberFormatException e) {
                System.out.println("坐标数据格式错误");
                throw new CommonException("坐标数据格式错误");
            }
        }

        // 获取当前时间的LocalTime和DayOfWeek
        LocalTime currentLocalTime = getCurrentLocalTime(date);
        int currentDayOfWeek = DateUtil.dayOfWeek(date) - 1;

        // 获取提醒周期的起始和结束时间以及DayOfWeek
        LocalTime startTime = getLocalTimeFromInstant(remindCycles.get(0).getStartTime().toInstant());
        LocalTime endTime = getLocalTimeFromInstant(remindCycles.get(0).getEndTime().toInstant());
        int remindCycleDayOfWeek = remindCycles.get(0).getDayOfWeek();

        // 判断当前时间是否在提醒周期内且当前日期为提醒周期的指定星期
        if (currentDayOfWeek == remindCycleDayOfWeek && isCurrentTimeInInterval(currentLocalTime, startTime, endTime)) {
            grainPriceCollect.setIsInRemindCycle(1);
        } else {
            grainPriceCollect.setIsInRemindCycle(0);
        }

        QueryWrapper<GrainPriceCollect> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("price_monitor_id",grainPriceCollectAddParam.getPriceMonitorId());
        queryWrapper.eq("user_collect_date",DateUtil.format(date,"yyyy-MM-dd"));
        List<GrainPriceCollect> collectList  = this.list(queryWrapper);
        if (collectList.size() > 0 ){
            GrainPriceCollect grainPriceCollect2 = collectList.get(0);
            if (grainPriceCollect2.getAuditStatus() != 2){
                throw new CommonException("不能重复上报");
            }
            Integer isInRemindCycle = grainPriceCollect.getIsInRemindCycle();
            grainPriceCollect =  collectList.get(0);
            grainPriceCollect.setIsInRemindCycle(isInRemindCycle);
            grainPriceCollect.setAuditStatus(0);
            grainPriceCollect.setUserCollectDateCount(grainPriceCollect.getUserCollectDateCount()+1);
            //删除品种数据
            QueryWrapper<GrainPriceCollectCategory> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("type_id",grainPriceCollect.getId());

            if ( !grainPriceCollectCategoryService.remove(queryWrapper1)){
                throw new CommonException("删除品种数据失败");
            }
        }


        grainPriceCollect.setUserCollectDate(date);

        //得到品种价格采集信息
        this.saveOrUpdate(grainPriceCollect);
        //价格采集主键id
        String id = grainPriceCollect.getId();
        //检测是否有备注
        Boolean isRemark = StringUtils.isBlank(grainPriceCollect.getRemark()); //
        List<GrainPriceCollectCategoryAddParam>  categoryAddParamList = grainPriceCollectAddParam.getCategoryAddParamList();
        List<GrainPriceCollectCategory> categoryList = new ArrayList<>();
        for (int i = 0; i <categoryAddParamList.size() ; i++) {
            //得到价格品种数据
            GrainPriceCollectCategory category =  BeanUtil.toBean(categoryAddParamList.get(i),GrainPriceCollectCategory.class);
            if (category.getPrice() ==null){ //价格不允许为空，价格为空不进行保存
                continue;
            }
            category.setType(Integer.parseInt(GrainPriceCollectTypeEnum.PriceCollect.getValue()));
            category.setTypeId(id);
            //没有备注，进行检测
            if (isRemark) {
                boolean isOver = comparePrice(grainPriceCollect, category);
                if (isOver){
                    throw new CommonException("本周/月汇总粮食平均价超出上周/月汇总粮食平均价5%以上，需要填报备注说明，否则不能上报");
                }
            }
            categoryList.add(category);
        }
        grainPriceCollectCategoryService.saveOrUpdateBatch(categoryList);
    }
    //得到最新相同相同监测点，同品种，同价格类型的价格采集时间最近的一条数据
    private boolean comparePrice(GrainPriceCollect grainPriceCollect, GrainPriceCollectCategory category) {

        List<Map<String,Object>> categoryList1 = grainPriceCollectMapper.getOffPrice(grainPriceCollect.getId(),grainPriceCollect.getPriceMonitorId().toString(),category.getType().toString(),
                category.getPriceType().toString(),
                category.getFirstLevel().toString(),
                category.getSecondLevel().toString(),
                category.getThreeLevel().toString()
        );
        //未查到最新一条数据，表示是第一次录入，直接检测通过
        BigDecimal offPrice ;
        if (categoryList1.size() == 1){
            //得到上一期间价格
            offPrice  = NumberUtil.toBigDecimal(categoryList1.get(0).get("offPrice").toString());
        }else{
            return  false;
        }
        //得到本期价格
        BigDecimal avgPrice  = category.getPrice();
        //与上周同期比 =（本期间平价价格-上期间平价价格）/本期间平价价格
        BigDecimal weekRate  =  NumberUtil.div(NumberUtil.sub(avgPrice,offPrice),avgPrice);
//        本周/月汇总粮食平均价超出上周/月汇总粮食平均价5%以上，需要填报备注说明，否则不能上报。
//        如果今日汇总粮食平均价超出上日粮食平均价2%以上，需要填报备注说明，否则不能上报。
        return NumberUtil.compare(weekRate.doubleValue(),NumberUtil.parseDouble("0.05")) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(GrainPriceCollectEditParam grainPriceCollectEditParam) {
        GrainPriceCollect grainPriceCollect = this.queryEntity(grainPriceCollectEditParam.getId());
        String priceMonitorId = grainPriceCollect.getPriceMonitorId();
        if(ObjectUtil.isEmpty(grainPriceCollect)) {
            throw new CommonException("粮食价格采集不存在，id值为：{}", grainPriceCollect.getId());
        }
        //表示已经审核
        if(grainPriceCollect.getAuditStatus() == 1 ) {
            throw new CommonException("粮食价格采集已审核，id值为：{}", grainPriceCollect.getId());
        }
        List<GrainPriceCollectCategoryEditParam>  categoryEditParamList = grainPriceCollectEditParam.getCategoryEditParamList();
        if(categoryEditParamList ==null || categoryEditParamList.size() <= 0) {
            throw new CommonException("粮食价格采集价格不能为空，id值为：{}", grainPriceCollect.getId());
        }
        grainPriceCollectEditParam.setUserCollectDateCount(grainPriceCollect.getUserCollectDateCount()+1);
        BeanUtil.copyProperties(grainPriceCollectEditParam, grainPriceCollect);
        //设置监测点
        grainPriceCollect.setPriceMonitorId(priceMonitorId);
        this.updateById(grainPriceCollect);

        //检测是否有备注
        Boolean isRemark = StringUtils.isBlank(grainPriceCollect.getRemark()); //
        //得到采集价格品种
        String id = grainPriceCollect.getId();
        //先删除历史数据
        QueryWrapper<GrainPriceCollectCategory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type_id",id);
        List<GrainPriceCollectCategory> categoryList = new ArrayList<>();
        if ( grainPriceCollectCategoryService.list(queryWrapper).size() >0){
            if ( !grainPriceCollectCategoryService.remove(queryWrapper)){
                throw new CommonException("清理粮食价格品种数据失败");
            }
        }
        for (int i = 0; i <categoryEditParamList.size() ; i++) {
            //得到价格品种数据
            GrainPriceCollectCategory category =  BeanUtil.toBean(categoryEditParamList.get(i),GrainPriceCollectCategory.class);
            category.setTypeId(id);
            //没有备注，进行检测
            if (isRemark) {
                boolean isOver = comparePrice(grainPriceCollect, category);
                if (isOver){
                    throw new CommonException("本周/月汇总粮食平均价超出上周/月汇总粮食平均价5%以上，需要填报备注说明，否则不能上报");
                }
            }
            categoryList.add(category);
        }
        grainPriceCollectCategoryService.saveOrUpdateBatch(categoryList);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(GrainPriceCollectIdParam grainPriceCollectIdParam) {
        GrainPriceCollect grainPriceCollect = this.queryEntity(grainPriceCollectIdParam.getId());
        if(ObjectUtil.isEmpty(grainPriceCollect)) {
            throw new CommonException("粮食价格采集不存在，id值为：{}", grainPriceCollect.getId());
        }
        //表示已经审核
        if(grainPriceCollect.getAuditStatus() == 1) {
            throw new CommonException("粮食价格采集已审核，id值为：{}", grainPriceCollect.getId());
        }
            // 执行删除
        this.removeById(grainPriceCollectIdParam.getId());
        //删除采集价格品种数据
        QueryWrapper<GrainPriceCollectCategory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type_id",grainPriceCollectIdParam.getId());
        grainPriceCollectCategoryService.remove(queryWrapper);
    }

    @Override
    public GrainPriceCollect detail(GrainPriceCollectIdParam grainPriceCollectIdParam) {
        return this.queryEntity(grainPriceCollectIdParam.getId());
    }

    @Override
    public GrainPriceCollect queryEntity(String id) {
        GrainPriceCollect grainPriceCollect = this.getById(id);
        if(ObjectUtil.isEmpty(grainPriceCollect)) {
            throw new CommonException("粮食价格采集不存在，id值为：{}", id);
        }
        //得到采集价格品种
        QueryWrapper<GrainPriceCollectCategory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type_id",id);
        //按一级，二级，三级，价格类型排序
        queryWrapper.orderByAsc("first_level,second_level,three_level,price_type");
        List<GrainPriceCollectCategory> collectCategoryList  = grainPriceCollectCategoryService.list(queryWrapper);
        grainPriceCollect.setCollectCategoryList(collectCategoryList);
        return grainPriceCollect;
    }

    /**
     * 获取粮监测点信息
     * * @author TS
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> getMonitorInfo() {
        //得到token中的用户信息，进行处理
        UserCollectLogin userCollectLogin = (UserCollectLogin)StpClientUtil.getTokenSession().get("loginUser");

        List<Map<String, Object>> monitorInfos = grainPriceCollectMapper.getMonitorInfo(userCollectLogin.getId().toString());
        return monitorInfos;
    }

    /**
     * 获取当前用户最近粮监测点信息
     *
     * @param point
     * @return
     */
    @Override
    public Map<String, Object> getMonitorInfoByPoint(String point) {
        //得到token中的用户信息，进行处理
        UserCollectLogin userCollectLogin = (UserCollectLogin)StpClientUtil.getTokenSession().get("loginUser");

        Map<String, Object> monitorInfo = grainPriceCollectMapper.getMonitorInfoByPoint(userCollectLogin.getId().toString(),point);
        if (monitorInfo == null || monitorInfo.isEmpty()) {
            // 设置返回消息，这里可以使用自定义消息类、Map、JSON对象等格式
            Map<String, Object> response = new HashMap<>();
            response.put("status", "error");
            response.put("message", "不在采集范围内");
            // 返回该消息
            return response;
        }
        return monitorInfo;
    }

    /**
     * 获取自定义粮食价格采集分页
     *
     * @param pageParam
     * @return
     */
    @Override
    public IPage<Map<String, Object>> findPage(GrainPriceCollectPageParam pageParam) {
        //条形查询器
        QueryWrapper<GrainPriceCollectCitySum> queryWrapper = new QueryWrapper<>();

        //PC管理端才涉及数据范围，app不在组织架构中，不涉及数据权限
//        if(pageParam.getIsApp() == null || pageParam.getIsApp() != 1){
//            // 校验数据范围
//            List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
//            if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
//                //数据范围不为空，则查询这些机构内的
//                queryWrapper.in("b.sys_org_id", loginUserDataScope);
//            } else {
//                //否则只查询自己的
//            queryWrapper.in("a.user_collect_id", StpUtil.getLoginIdAsString());
//                return new Page<>();
//            }
//        }

        //分页相关
        if(StringUtils.isNotBlank(pageParam.getMonitorName())){
            queryWrapper.like("b.name",pageParam.getMonitorName() );
        }
        if(pageParam.getStatus() != null && pageParam.getStatus() >= 0){
            queryWrapper.eq("a.audit_status",pageParam.getStatus() );
        }
        //app列表只展示当天数据
        if(pageParam.getIsApp() != null && pageParam.getIsApp() == 1){
            //app只查询自己的
            //得到token中的用户信息，进行处理
            UserCollectLogin userCollectLogin = (UserCollectLogin)StpClientUtil.getTokenSession().get("loginUser");

            if (userCollectLogin == null  && StringUtils.isBlank(userCollectLogin.getId().toString())){
                return new Page<>();
            }
            queryWrapper.eq("a.user_collect_id", userCollectLogin.getId());

            queryWrapper.apply(" DATE_FORMAT(ifnull(a.user_collect_date,NOW()),'%Y-%m-%d') =  DATE_FORMAT(NOW(),'%Y-%m-%d')");
        }
        Page<GrainPriceCollectCitySum> p =new Page<>(pageParam.getCurrent(),pageParam.getSize());


        IPage<Map<String,Object>> page = grainPriceCollectMapper.selectMyMapsPage(p,queryWrapper);
        return page;
    }

    /**
     * 审核粮食价格采集
     *
     * @param idParam
     * @return
     */
    @Override
    public String audit(GrainPriceCollectIdParam idParam) {
        GrainPriceCollect grainPriceCollect = this.getById(idParam.getId());
        if(ObjectUtil.isEmpty(grainPriceCollect)) {
            throw new CommonException("粮食价格采集不存在，id值为：{}", grainPriceCollect.getId());
        }
        //表示已经审核,并且不能再次审核
        if(grainPriceCollect.getAuditStatus() == 1 && idParam.getAuditStatus() == 1) {
            throw new CommonException("粮食价格采集已审核，id值为：{}", grainPriceCollect.getId());
        }
        if(idParam.getAuditStatus() == 2){ //表示是驳回
            if(grainPriceCollect.getAuditStatus() == 2) {
                throw new CommonException("粮食价格采集已驳回，id值为：{}", grainPriceCollect.getId());
            }
            //检测市级是否汇总.如果省级已经汇总，则必须市级已处于驳回并且删除省级汇总才行
            if ( StringUtils.isNotBlank(grainPriceCollect.getGrainPriceCollectCityId()) ){

                GrainPriceCollectCitySum citySum =  grainPriceCollectCitySumService.getById(grainPriceCollect.getGrainPriceCollectCityId());
                if (ObjectUtil.isNotEmpty(citySum)){
                    if (citySum.getGrainPriceCollectProvinceSumId() != null ){
                        throw new CommonException("市级汇总必须驳回后才可进行价格采集驳回！");
                    }
                }
            }
            if(StringUtils.isBlank(idParam.getAuditRejectAdvice())){
                throw new CommonException("驳回必须填写驳回意见！");
            }
        }
        grainPriceCollect.setAuditStatus(idParam.getAuditStatus());
        if (StringUtils.isNotBlank(idParam.getAuditRejectAdvice())){
            grainPriceCollect.setAuditRejectAdvice(idParam.getAuditRejectAdvice());
        }
        return this.updateById(grainPriceCollect)?"处理成功":"处理失败";
    }

    /*
       判断当前时间是不是和报送周期相同
    */
    private boolean isCurrentDateReportDay(Date currentDate, RemindCycle cycle) {
        int currentDayOfWeek = getAdjustedDayOfWeek(currentDate);
        return currentDayOfWeek == cycle.getDayOfWeek();
    }

    private int getAdjustedDayOfWeek(Date date) {
        return DateUtil.dayOfWeek(date) - 1;
    }
    /*
        时间转换
     */
    private LocalTime getCurrentLocalTime(Date date) {
        return toLocalTime(date.toInstant());
    }

    private LocalTime getLocalTimeFromInstant(Instant instant) {
        return toLocalTime(instant);
    }

    private LocalTime toLocalTime(Instant instant) {
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalTime();
    }
    /*
        判断在不在这个时间段内
     */
    private boolean isCurrentTimeInInterval(LocalTime currentLocalTime, LocalTime startTime, LocalTime endTime) {
        return currentLocalTime.isAfter(startTime) && currentLocalTime.isBefore(endTime);
    }

}
