package org.dromara.system.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.timingwheel.SystemTimer;
import cn.hutool.cron.timingwheel.TimerTask;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.service.WxPayService;
import jakarta.annotation.PostConstruct;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.TblDzbcOrderLogBo;
import org.dromara.system.domain.bo.TblDzbcPathSchedulingBo;
import org.dromara.system.domain.vo.*;
import org.dromara.system.mapper.*;
import org.dromara.util.DistanceCalculator;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.TblDzbcOrderBo;
import org.dromara.system.service.ITblDzbcOrderService;
import org.springframework.util.Assert;

import java.util.*;

/**
 * 定制班车-订单Service业务层处理
 *
 * @author Lion Li
 * @date 2025-02-12
 */
@RequiredArgsConstructor
@Service
public class TblDzbcOrderServiceImpl implements ITblDzbcOrderService {

    private final TblDzbcOrderMapper baseMapper;
    private final TblDzbcSiteMapper siteMapper;
    private final TblDzbcOrderLogMapper orderLogMapper;
    private final SysConfigMapper sysConfigMapper;
    private final TblDzbcAreaMapper areaMapper;
    private final TblDzbcPathSchedulingMapper pathSchedulingMapper;
    private final TblDzbcPathMapper pathMapper;
    private final TblDzbcMultiSitePathMapper multiSitePathMapper;
    private final TblDzbcSitePriceMapper sitePriceMapper;




    /**
     * 查询定制班车-订单
     */
    @Override
    public TblDzbcOrderVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询定制班车-订单列表
     */
    @Override
    public TableDataInfo<TblDzbcOrderVo> queryPageList(TblDzbcOrderBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TblDzbcOrder> lqw = buildQueryWrapper(bo);
        Page<TblDzbcOrderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        SysUserMapper userMapper = SpringUtils.getBean(SysUserMapper.class);
        Map<Long, SysUser> userMap = new HashMap<>();
        userMapper.selectList().forEach(user -> {
            userMap.put(user.getUserId(), user);
        });
        result.getRecords().forEach(order -> {
            try {
                order.setUserPhone(userMap.get(order.getUserId()).getUserName());
            } catch (Exception e) {

            }

        });

        return TableDataInfo.build(result);
    }

    /**
     * 查询定制班车-订单列表
     */
    @Override
    public List<TblDzbcOrderVo> queryList(TblDzbcOrderBo bo) {
        LambdaQueryWrapper<TblDzbcOrder> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public List<TblDzbcOrderVo> queryListByGroup(TblDzbcOrderBo bo) {
        bo.getParams().put("orderByTime", "1");
        LambdaQueryWrapper<TblDzbcOrder> lqw = buildQueryWrapper(bo);
        return baseMapper.queryListByGroup(bo, lqw);
    }



    private LambdaQueryWrapper<TblDzbcOrder> buildQueryWrapper(TblDzbcOrderBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TblDzbcOrder> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getName()), TblDzbcOrder::getName, bo.getName());
        lqw.eq(bo.getId() != null, TblDzbcOrder::getId, bo.getId());
        lqw.eq(bo.getUserId() != null, TblDzbcOrder::getUserId, bo.getUserId());
        lqw.eq(bo.getSchedulingId() != null, TblDzbcOrder::getSchedulingId, bo.getSchedulingId());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TblDzbcOrder::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getStartInfo()), TblDzbcOrder::getStartInfo, bo.getStartInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getEndInfo()), TblDzbcOrder::getEndInfo, bo.getEndInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getExt1()), TblDzbcOrder::getExt1, bo.getExt1());
        lqw.eq(StringUtils.isNotBlank(bo.getExt2()), TblDzbcOrder::getExt2, bo.getExt2());

        if(params==null||params.get("orderByTime") == null){
            lqw.orderBy(true, false,TblDzbcOrder::getCreateTime);
        }
        try{
            if(params!=null&&params.containsKey("mdate")){
                lqw.ge(params.get("mdate")!=null, TblDzbcOrder::getCreateTime, params.get("mdate").toString());
            }
        } catch (Exception e) {

        }

        if(params!=null && params.containsKey("kyzId")){
            String datasql = "( select id from tbl_dzbc_car where kyz_id = "+bo.getParams().get("kyzId").toString()+")";
            lqw.apply(StringUtils.format(" scheduling_id in {}", datasql));
        }

        return lqw;
    }


    /**
     * 新增定制班车-订单
     */
    @Override
    public TblDzbcOrderBo insertByBo(TblDzbcOrderBo bo) {
        TblDzbcOrder add = MapstructUtils.convert(bo, TblDzbcOrder.class);
        validEntityBeforeSave(add);
        Assert.isTrue(bo.getSchedulingId()!=null,"缺少路线班次");
        TblDzbcPathSchedulingVo scheduling = pathSchedulingMapper.selectVoById(bo.getSchedulingId());
        Assert.isTrue(scheduling!=null,"路线未查询到排班");

        // 解析排班类型
        Integer type = null;
        if (scheduling.getExt2() != null) {
            try {
                JSONObject ext2 = JSONUtil.parseObj(scheduling.getExt2());
                if (ext2.containsKey("type")) {
                    type = ext2.getInt("type");
                }
            } catch (Exception e) {}
        }

        // 预定义变量
        String pathName = "";
        TblDzbcPathVo pathVo = null;
        TblDzbcMultiSitePathVo multiPathVo = null;

        if (type != null && type == 2) {
            // === 多站点路线 ===
            multiPathVo = multiSitePathMapper.selectVoById(scheduling.getPathId());
            Assert.isTrue(multiPathVo != null, "路线不存在");
            pathName = multiPathVo.getName();
            // 多站点路线使用排班自带的 mtime，无需回退到 pathVo.mtime
        } else {
            // === 普通路线 ===
            pathVo = pathMapper.selectVoById(scheduling.getPathId());
            Assert.isTrue(pathVo!=null,"路线不存在");
            pathName = pathVo.getName();
            // 如果排班没有时间，使用路线默认时间
            if(scheduling.getMtime()==null || scheduling.getMtime().equals("")){
                scheduling.setMtime(pathVo.getMtime());
            }
        }

        Assert.isTrue(bo.getNum()!=null,"缺少座位数");
//        Assert.isTrue(bo.getParams().get("usersInfo")!=null,"缺少订购人员");
        if(bo.getParams().get("usersInfo")==null){
            bo.getParams().put("usersInfo",new Object[]{});
        }

        Date datec =  DateUtil.parse(DateUtil.formatDate(scheduling.getMdate())+" "+scheduling.getMtime(), DatePattern.NORM_DATETIME_FORMAT);
        Assert.isTrue( datec.getTime() > DateUtil.current(),"路线车辆已出发");

        Assert.isTrue(bo.getParams().get("startSiteId")!=null,"缺少出发站点");
        Assert.isTrue(bo.getParams().get("endSiteId")!=null,"缺少目的站点");
        //查询起点  //查询终点
        TblDzbcSiteVo startSite = siteMapper.selectVoById(Long.parseLong(bo.getParams().get("startSiteId").toString()));
        TblDzbcSiteVo endSite =  siteMapper.selectVoById(Long.parseLong(bo.getParams().get("endSiteId").toString()));
        Assert.isTrue(startSite!=null&&endSite!=null,"站点Id不存在");

        //查询起点区域到目前区域的距离
        List<TblDzbcAreaVo> areas = areaMapper.selectVoBatchIds(List.of(startSite.getAreaId(),endSite.getAreaId()));
        // 注意：如果是同区域，areas.size() 可能为 1 (如果去重) 或 2 (如果未去重但ID相同)。
        // 为了安全起见，分别查询或者处理 size < 2 的情况。
        // 但为了兼容旧代码逻辑，这里先保留，但在多站点且同区域时可能会有问题。
        // 如果是多站点且同区域，areas.size() 会是 1 (MyBatis-Plus batchIds 会去重)。
        // 所以需要重新处理 areas 获取逻辑。

        TblDzbcAreaVo startArea = null;
        TblDzbcAreaVo endArea = null;
        if (startSite.getAreaId().equals(endSite.getAreaId())) {
             startArea = areaMapper.selectVoById(startSite.getAreaId());
             endArea = startArea;
        } else {
             // 保持原有逻辑以防万一，或者分别查询
             startArea = areaMapper.selectVoById(startSite.getAreaId());
             endArea = areaMapper.selectVoById(endSite.getAreaId());
        }
        Assert.isTrue(startArea != null && endArea != null, "区域信息错误");

        if (type != null && type == 2) {
            // === 多站点路线价格计算 ===
            TblDzbcSitePriceVo priceVo = sitePriceMapper.selectVoOne(
                new LambdaQueryWrapper<TblDzbcSitePrice>()
                    .eq(TblDzbcSitePrice::getPathId, scheduling.getPathId())
                    .eq(TblDzbcSitePrice::getFromSiteId, startSite.getId())
                    .eq(TblDzbcSitePrice::getToSiteId, endSite.getId())
            );
            if (priceVo == null) {
                 throw new RuntimeException("未查询到该行程的票价信息");
            }
            int finalResult = Math.round(((int)Math.round(priceVo.getPrice() + scheduling.getPprice()) + 5) / 100) * 100;
            add.setPrice(finalResult);

        } else {
            // === 普通路线逻辑 ===
            Assert.isTrue(!startSite.getAreaId().equals(endSite.getAreaId()),"站点不在能在同一区域");

            Assert.isTrue(StrUtil.isNotEmpty(startArea.getLocation()) ,startArea.getName()+"区域未设置经纬度");
            Assert.isTrue(StrUtil.isNotEmpty(endArea.getLocation()),endArea.getName()+"区域未设置经纬度");
            double distanceArea = DistanceCalculator.calculateDistance(startArea.getLocation(),endArea.getLocation());
            double distanceSite = DistanceCalculator.calculateDistance(startSite.getLocation(),endSite.getLocation());

            try{
                if(pathVo.getExt1()!=null && JSONUtil.parseObj(pathVo.getExt1().toString())!=null) {
                    JSONObject ext1 = JSONUtil.parseObj(pathVo.getExt1().toString());
                    //获取区域价格
                    JSONArray prices = ext1.getJSONArray("jgqj");
                    //获取距离
                    Double distance = ext1.getDouble("jl");
                    //获取价格系数
                    Double jgxs = ext1.getDouble("jgxs");

                    if (jgxs == null) jgxs = 1.0;
                    if (distance == null) distance = distanceArea;
                    double distanceSite1 = distanceSite * distance / distanceArea;

                    if(prices!=null||prices.size()>0) {
                        for (int i = 0; i < prices.size(); i++) {
                            JSONObject price = prices.getJSONObject(i);
                            Double min = price.getDouble("min");
                            Double max = price.getDouble("max");
                            Double xs = price.getDouble("xs");
                            Double p = price.getDouble("price");
                            if (min == null) min = 0.0;
                            if (max == null) max = Double.MAX_VALUE;
                            if (xs == null) xs = 0.0;
                            if (distanceSite1 >= min && distanceSite1 <= max) {
                                double jg = (p * 100) + (((distanceSite1-min)/1000.0) * xs)*100;
                                int finalResult = Math.round(((int) Math.round(jg) + 5) / 100) * 100;
                                add.setPrice(finalResult);
                                break;
                            }
                        }
                    }
                }
            }catch (Exception e){
                throw new RuntimeException("路线价格错误");
            }
            if(add.getPrice()==null){
                Integer price1 = pathVo.getPrice();
                if(price1==null) throw new RuntimeException("路线价格错误");
                //单价 根据区域-区域 单价及站点-站点 计算价格
                double price = price1*(distanceSite/distanceArea);
                //计算加价
                int finalResult = Math.round(((int)Math.round(price+scheduling.getPprice()) + 5) / 100) * 100;
                add.setPrice(finalResult);
            }
        }

        add.setStartInfo(JSONUtil.toJsonStr(Map.of("areaInfo", startArea, "siteInfo", startSite)));
        add.setEndInfo(JSONUtil.toJsonStr(Map.of("areaInfo", endArea, "siteInfo", endSite)));

        add.setUserId(LoginHelper.getUserId());

        add.setName(DateUtil.formatDate(scheduling.getMdate())+" "+pathName+" "+scheduling.getMtime());
        //计算总价
        add.setTotalPrice(add.getNum()*add.getPrice());

        bo.getParams().put("zw",add.getNum());
        add.setExt1(JSONUtil.toJsonStr(Map.of("zw", add.getNum(),"usersInfo",bo.getParams().get("usersInfo"),"startSiteId",bo.getParams().get("startSiteId"),"endSiteId",bo.getParams().get("endSiteId"))));

        scheduling.setStartSites(null);
        scheduling.setEndSites(null);
        add.setExt2(JSONUtil.toJsonStr(Map.of("schedulInfo", scheduling)));

        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            try {
                TblDzbcOrderLog orderLogBo = new TblDzbcOrderLog();
                orderLogBo.setOrderId(bo.getId());
                orderLogBo.setExt1(JSONUtil.toJsonStr(bo));
                orderLogMapper.insert(orderLogBo);
            } catch (Exception e) {
            }
        }
        cacleOrder();
        return bo;
    }

    /**
     * 修改定制班车-订单
     */
    @Override
    public Boolean updateByBo(TblDzbcOrderBo bo) {
        TblDzbcOrder update = MapstructUtils.convert(bo, TblDzbcOrder.class);
        validEntityBeforeSave(update);

        try {
            TblDzbcOrderLog orderLogBo = new TblDzbcOrderLog();
            orderLogBo.setOrderId(bo.getId());
            orderLogBo.setExt1(JSONUtil.toJsonStr(update));
            orderLogMapper.insert(orderLogBo);
        } catch (Exception e) {

        }
        int c = baseMapper.updateById(update);
        if(bo.getId()!=null && bo.getStatus()!=null){
            //跟新路线站点信息
            ThreadUtil.execAsync(new Runnable() {
                @Override
                public void run() {
                    //获取所有订单为2的订单
                    //先获取当前点的的路线ID
                    TblDzbcOrderVo entity = queryById(bo.getId());
                    if(entity!=null){
                        TblDzbcOrderBo bo1 = new TblDzbcOrderBo();
                        bo1.setSchedulingId(entity.getSchedulingId());
                        bo1.setStatus("1");
                        List<TblDzbcOrderVo> list = queryList(bo1);
                        //查出所有订单的startInfo和endInfo
                        //{"areaInfo": {"id": 1889580334985953281, "addr": "ss", "ext1": "{}", "ext2": "{}", "name": "松罗", "kyzId": 1889579208173600769, "remark": "nulla deserunt minim tempor", "location": "119.61157136502725,27.179696949640462"}, "siteInfo": {"id": 1889579608918376450, "addr": "是多少", "ext1": "{}", "ext2": "{}", "name": "万达公交站", "areaId": 1889580334985953281, "remark": "ut nulla sint", "location": "119.70444636953097,27.142621940313745"}}

                        Map<Long, Object> startSites = new HashMap<>();
                        Map<Long, Object> endSites = new HashMap<>();



                        for (TblDzbcOrderVo tblDzbcOrderVo : list) {
                            Map<String,Object> startsite = new HashMap<>();
                            JSONObject siteJson = JSONUtil.parseObj(tblDzbcOrderVo.getStartInfo()).getJSONObject("siteInfo");
                            try {
                                if(startSites.get(siteJson.getLong("id"))!=null){
                                    startsite = (Map<String, Object>) startSites.get(siteJson.getLong("id"));
                                }
                            } catch (Exception e) {
                            }
                            startsite.put("siteInfo",siteJson);
                            startsite.put(StringUtils.format("order-{}", tblDzbcOrderVo.getId().toString()),tblDzbcOrderVo.getExt1());
                            startSites.put(siteJson.getLong("id"),startsite);



                            Map<String,Object> endsite = new HashMap<>();
                            JSONObject siteJson1 = JSONUtil.parseObj(tblDzbcOrderVo.getEndInfo()).getJSONObject("siteInfo");
                            try {
                                if(endSites.get(siteJson1.getLong("id"))!=null){
                                    endsite = (Map<String, Object>) endSites.get(siteJson1.getLong("id"));
                                }
                            } catch (Exception e) {
                            }
                            endsite.put("siteInfo",siteJson1);
                            endsite.put(StringUtils.format("order-{}", tblDzbcOrderVo.getId().toString()),tblDzbcOrderVo.getExt1());
                            endSites.put(siteJson1.getLong("id"),endsite);
                        }
                        //跟新路线
                        TblDzbcPathScheduling sbo1 = new TblDzbcPathScheduling();
                        sbo1.setId(entity.getSchedulingId());
                        sbo1.setStartSites(JSONUtil.toJsonStr(startSites));
                        sbo1.setEndSites(JSONUtil.toJsonStr(endSites));
                        pathSchedulingMapper.updateById(sbo1);

                    }



                }
            });

        }


        return  c> 0;
    }



    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TblDzbcOrder entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除定制班车-订单
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }




    public void cacleOrder(){
        //获取所有订单
        TblDzbcOrderBo bo = new TblDzbcOrderBo();
        bo.setStatus("0");
        List<TblDzbcOrder>  list = baseMapper.selectList(buildQueryWrapper(bo));
        for (TblDzbcOrder tblDzbcOrder : list) {
            if(System.currentTimeMillis()-tblDzbcOrder.getCreateTime().getTime()>=1000*60*30){
                TblDzbcOrderBo bo1 = new TblDzbcOrderBo();
                bo1.setId(tblDzbcOrder.getId());
                bo1.setStatus("5");
                updateByBo(bo1);
            }else{
                SystemTimer timer = new SystemTimer();
                timer.start();
                timer.addTask(new TimerTask(()->{
                    TblDzbcOrderBo bo1 = new TblDzbcOrderBo();
                    bo1.setId(tblDzbcOrder.getId());
                    List<TblDzbcOrder> list1 =baseMapper.selectList(buildQueryWrapper(bo1));
                    if(list1.size()>0){
                        if(list1.get(0).getStatus().equals("0")){
                            bo1.setStatus("5");
                            updateByBo(bo1);
                        }
                    }

                },1000*60*30-(System.currentTimeMillis()-tblDzbcOrder.getCreateTime().getTime())));
            }
        }
    }

    @PostConstruct
    public void init(){

        cacleOrder();

    }
}
