package com.multictrl.modules.business.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.multictrl.common.constant.BusinessConstant;
import com.multictrl.common.constant.Constant;
import com.multictrl.common.constant.DJIImage;
import com.multictrl.common.constant.DockMode;
import com.multictrl.common.exception.ErrorCode;
import com.multictrl.common.exception.RenException;
import com.multictrl.common.page.PageData;
import com.multictrl.common.utils.CacheUtils;
import com.multictrl.common.utils.ConvertUtils;
import com.multictrl.common.utils.MessageUtils;
import com.multictrl.modules.business.dao.MultiGroupDao;
import com.multictrl.modules.business.dao.MultiGroupDeviceDao;
import com.multictrl.modules.business.dto.DockDTO;
import com.multictrl.modules.business.dto.flight.FlightExecute;
import com.multictrl.modules.business.dto.multi.MultiDockDTO;
import com.multictrl.modules.business.dto.multi.MultiGroupDTO;
import com.multictrl.modules.business.dto.multi.MultiGroupDeviceDTO;
import com.multictrl.modules.business.dto.multi.MultiTaskDTO;
import com.multictrl.modules.business.dto.multi.PrivateMultiFlightBindDockInfo;
import com.multictrl.modules.business.entity.DeviceDicEntity;
import com.multictrl.modules.business.entity.DockDeviceEntity;
import com.multictrl.modules.business.entity.MultiGroupDeviceEntity;
import com.multictrl.modules.business.entity.MultiGroupEntity;
import com.multictrl.modules.business.service.DJIBaseService;
import com.multictrl.modules.business.service.DockService;
import com.multictrl.modules.business.service.MultiService;
import com.multictrl.modules.business.service.RouteFlightService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.multictrl.modules.sys.dao.SysDictDataDao;
import com.multictrl.modules.sys.entity.SysDictDataEntity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 阿罗斯机场 蛙跳
 *
 * @author 张闯
 * @since 2026-05-28
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MultiServiceImpl implements MultiService {
    private final MultiGroupDao multiGroupDao;
    private final MultiGroupDeviceDao multiGroupDeviceDao;
    private final DJIBaseService djiBaseService;
    private final RouteFlightService routeFlightService;
    private final DockService dockService;
    private final SysDictDataDao dictDataDao;

    @Override
    public PageData<DockDTO> pageList(Map<String, Object> params) {
        List<MultiGroupDeviceEntity> multiGroupDeviceEntities = multiGroupDeviceDao.selectList(null);
        List<String> dockSns = null;
        if (CollUtil.isNotEmpty(multiGroupDeviceEntities)) {
            dockSns = multiGroupDeviceEntities.stream().map(MultiGroupDeviceEntity::getGatewaySn).toList();
        }
        params.put("dockSns", dockSns);
        PageData<DockDTO> page = dockService.page(params);
        addDockProperty(page.getList());
        return page;
    }

    @Override
    public PageData<MultiGroupDTO> pageMultiGroup(Map<String, Object> params) {
        long curPage = 1;
        long limit = 10;
        if (params.get(Constant.PAGE) != null) {
            curPage = Long.parseLong((String) params.get(Constant.PAGE));
        }
        if (params.get(Constant.LIMIT) != null) {
            limit = Long.parseLong((String) params.get(Constant.LIMIT));
        }
        //分页对象
        Page<MultiGroupEntity> page = new Page<>(curPage, limit);
        String groupName = (String) params.get("name");
        Page<MultiGroupEntity> selectPage = multiGroupDao.selectPage(page,
                new QueryWrapper<MultiGroupEntity>()
                        .eq(StrUtil.isNotBlank(groupName), "group_name", groupName)
                        .orderByDesc("update_date"));
        return new PageData<>(ConvertUtils.sourceToTarget(selectPage.getRecords(), MultiGroupDTO.class), selectPage.getTotal());
    }

    @Override
    public void saveMultiGroup(MultiGroupDTO multiGroupDTO) {
        MultiGroupEntity entity = ConvertUtils.sourceToTarget(multiGroupDTO, MultiGroupEntity.class);
        multiGroupDao.insert(entity);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveMultiGroupDevice(MultiGroupDeviceDTO multiGroupDeviceDTO) {
        Long groudId = multiGroupDeviceDTO.getGroudId();
        for (String gatewaySn : multiGroupDeviceDTO.getGatewaySns()) {
            MultiGroupDeviceEntity deviceEntity = new MultiGroupDeviceEntity();
            deviceEntity.setGroudId(groudId);
            deviceEntity.setGatewaySn(gatewaySn);
            multiGroupDeviceDao.insert(deviceEntity);
        }
    }

    @Override
    public void updateMultiGroup(MultiGroupDTO multiGroupDTO) {
        MultiGroupEntity entity = ConvertUtils.sourceToTarget(multiGroupDTO, MultiGroupEntity.class);
        multiGroupDao.updateById(entity);
    }

    /*@Override
    public void updateMultiGroupDevice(MultiGroupDeviceDTO multiGroupDeviceDTO) {

    }*/

    @Override
    public void deleteMultiGroupDevice(List<Long> ids) {
        multiGroupDeviceDao.deleteByIds(ids);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteMultiGroup(List<Long> ids) {
        //删除组
        multiGroupDao.deleteByIds(ids);

        //删除机库组关系
        multiGroupDeviceDao.delete(new QueryWrapper<MultiGroupDeviceEntity>().in("group_id", ids));
    }

    @Override
    public List<DockDTO> getMultiGroupDockList(String multiGroupId) {
        List<MultiGroupDeviceEntity> multiGroupDeviceEntities = multiGroupDeviceDao.selectList(new QueryWrapper<MultiGroupDeviceEntity>()
                .eq("group_id", multiGroupId).orderByDesc("update_date"));
        if (CollUtil.isEmpty(multiGroupDeviceEntities)) {
            return List.of();
        }
        List<String> dockSns = multiGroupDeviceEntities.stream().map(MultiGroupDeviceEntity::getGatewaySn).toList();
        Map<String, Object> params = new HashMap<>();
        params.put("dockSns", dockSns);
        List<DockDTO> list = dockService.list(params);
        addDockProperty(list);
        return list;
    }

    @Override
    public String privateMultiDockTaskFlightTaskCheck(MultiTaskDTO multiTaskDTO) {
        for (MultiDockDTO multiDockDTO : multiTaskDTO.getDocks()) {
            if (multiDockDTO.getDockType().equals(BusinessConstant.MIAO_SUAN_SIGN)) {
                continue;
            }
            String result = privateMultiDockTaskFlightTaskCheck(multiDockDTO.getDockSn());
            log.info("privateMultiDockTaskFlightTaskCheck-> dockSn:{},result:{}", multiDockDTO.getDockSn(), result);
        }
        return MessageUtils.getMessage(ErrorCode.DOCK_EXEC_SUCCESS);
    }

    @Override
    public String privateMultiDockFlightTaskOutbound(MultiTaskDTO multiTaskDTO) {
        //第一步，调用所有机场出库
        for (MultiDockDTO multiDockDTO : multiTaskDTO.getDocks()) {
            if (multiDockDTO.getDockType().equals(BusinessConstant.MIAO_SUAN_SIGN)) {
                continue;
            }
            boolean need_drone_open = multiDockDTO.getDockSn()
                    .equals(multiTaskDTO.getMiaoSuanLocatedDock().getDockSn());
            String result = privateMultiDockFlightTaskOutbound(multiDockDTO.getDockSn(),
                    need_drone_open, multiTaskDTO.getMiaoSuan().getDockSn(), multiTaskDTO.getTaskId());
            log.info("privateMultiDockFlightTaskOutbound-> 调用所有机场出库 dockSn:{},result:{}",
                    multiDockDTO.getDockSn(),
                    result);
        }
        //第二步，检查机库各传感器状态，是否已经出库完成,180秒内
        int tryCount = 180;
        while (tryCount-- > 0) {
            boolean allFinished = true;
            for (MultiDockDTO multiDockDTO : multiTaskDTO.getDocks()) {
                if (multiDockDTO.getDockType().equals(BusinessConstant.MIAO_SUAN_SIGN)) {
                    continue;
                }
                Object o;
                if ((o = CacheUtils.get(BusinessConstant.DOCK_OSD + multiDockDTO.getDockSn())) == null) {
                    continue;
                }
                JSONObject jsonObject = (JSONObject) o;
                //cover_state 舱盖状态  {"0":"关闭","1":"打开","2":"半开","3":"舱盖状态异常"}
                int cover_state = jsonObject.getInt("cover_state");
                //putter_state 推杆状态 {"0":"关闭","1":"打开","2":"半开","3":"推杆状态异常"}
                int putter_state = jsonObject.getInt("putter_state");
                log.info(
                        "privateMultiDockFlightTaskOutbound-> 检查机库各传感器状态，是否已经出库完成 dockSn:{},cover_state:{},putter_state:{}"
                        , multiDockDTO.getDockSn(), cover_state, putter_state);
                allFinished = allFinished && cover_state == 1 && putter_state == 1;
            }
            if (allFinished) {
                break;
            }
        }
        if (tryCount <= 0) {
            return "出库超时";
        }
        //第三步，下发航线给psdk
        FlightExecute flightExecute = new FlightExecute();
        flightExecute.setTaskId(multiTaskDTO.getTaskId());
        flightExecute.setRouteId(multiTaskDTO.getRouteId());
        //获取每个机库的 经纬度/高度/备降点经纬度/备降点高度
        List<PrivateMultiFlightBindDockInfo> privateMultiFlightBindDockInfos = new ArrayList<>();
        for (MultiDockDTO multiDockDTO : multiTaskDTO.getDocks()) {
            if (multiDockDTO.getDockType().equals(BusinessConstant.MIAO_SUAN_SIGN)) {
                continue;
            }
            Object o;
            if ((o = CacheUtils.get(BusinessConstant.DOCK_OSD + multiDockDTO.getDockSn())) == null) {
                throw new RenException("机库: " + multiDockDTO.getDockSn() + "信息获取失败");
            }
            JSONObject jsonObject = (JSONObject) o;
            PrivateMultiFlightBindDockInfo privateMultiFlightBindDockInfo = new PrivateMultiFlightBindDockInfo();
            privateMultiFlightBindDockInfo.setDock_sn(multiDockDTO.getDockSn());
            privateMultiFlightBindDockInfo.setLongitude(jsonObject.getDouble("longitude"));
            privateMultiFlightBindDockInfo.setLatitude(jsonObject.getDouble("latitude"));
            privateMultiFlightBindDockInfo.setHeight(jsonObject.getDouble("height"));
            JSONObject alternate_land_point = jsonObject.getJSONObject("alternate_land_point");
            privateMultiFlightBindDockInfo.setAlternate_land_point_longitude(
                    alternate_land_point.getDouble("longitude"));
            privateMultiFlightBindDockInfo.setAlternate_land_point_latitude(alternate_land_point.getDouble("latitude"));
            privateMultiFlightBindDockInfo.setAlternate_land_point_height(alternate_land_point.getDouble("height"));
            privateMultiFlightBindDockInfo.setAlternate_land_point_safe_land_height(
                    alternate_land_point.getDouble("safe_land_height"));
            privateMultiFlightBindDockInfos.add(privateMultiFlightBindDockInfo);
        }
        flightExecute.setPrivateMultiFlightBindDockInfos(privateMultiFlightBindDockInfos);

        log.info("privateMultiDockFlightTaskOutbound-> 下发航线给妙算 flightExecute:{}", flightExecute);
        return routeFlightService.flightExecute(multiTaskDTO.getMiaoSuan().getDockSn(), flightExecute, true);
    }

    @Override
    public String privateMultiDockFlightTaskInbound(MultiTaskDTO multiTaskDTO) {
        //第一步，调用所有机场入库
        for (MultiDockDTO multiDockDTO : multiTaskDTO.getDocks()) {
            if (multiDockDTO.getDockType().equals(BusinessConstant.MIAO_SUAN_SIGN)) {
                continue;
            }
            boolean need_drone_close = multiDockDTO.getDockSn()
                    .equals(multiTaskDTO.getMiaoSuanLocatedDock().getDockSn());
            String result = privateMultiDockFlightTaskInbound(multiDockDTO.getDockSn(),
                    need_drone_close, multiTaskDTO.getMiaoSuan().getDockSn(), multiTaskDTO.getTaskId());
            log.info("privateMultiDockFlightTaskInbound-> dockSn:{},result:{}", multiDockDTO.getDockSn(),
                    result);
        }
        //第二步，判断所有机场的门都关闭了
        int tryCount = 180;
        while (tryCount-- > 0) {
            boolean allFinished = true;
            for (MultiDockDTO multiDockDTO : multiTaskDTO.getDocks()) {
                if (multiDockDTO.getDockType().equals(BusinessConstant.MIAO_SUAN_SIGN)) {
                    continue;
                }
                Object o;
                if ((o = CacheUtils.get(BusinessConstant.DOCK_OSD + multiDockDTO.getDockSn())) == null) {
                    continue;
                }
                JSONObject jsonObject = (JSONObject) o;
                //cover_state 舱盖状态  {"0":"关闭","1":"打开","2":"半开","3":"舱盖状态异常"}
                int cover_state = jsonObject.getInt("cover_state");
                log.info(
                        "privateMultiDockFlightTaskInbound-> 检查机库各传感器状态，是否已经入库完成 dockSn:{},cover_state:{}"
                        , multiDockDTO.getDockSn(), cover_state);
                allFinished = allFinished && cover_state == 0;
            }
            if (allFinished) {
                break;
            }
        }
        if (tryCount <= 0) {
            return "入库超时";
        }

        return "流程结束";
    }

    private String privateMultiDockTaskFlightTaskCheck(String dockSn) {
        return djiBaseService.executeAndReturnResult(dockSn, "private_multi_dock_task_flighttask_check");
    }

    private String privateMultiDockFlightTaskOutbound(String dockSn, boolean need_drone_open, String psdk_sn,
                                                      String task_id) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("need_drone_open", need_drone_open);
        jsonObject.set("psdk_sn", psdk_sn);
        jsonObject.set("task_id", task_id);
        return djiBaseService.executeAndReturnResult(dockSn, "private_multi_doc_dask_flighttask_outbound", jsonObject);
    }

    private String privateMultiDockFlightTaskInbound(String dockSn, boolean need_drone_close, String psdk_sn,
                                                     String task_id) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("need_drone_close", need_drone_close);
        jsonObject.set("psdk_sn", psdk_sn);
        jsonObject.set("task_id", task_id);
        return djiBaseService.executeAndReturnResult(dockSn, "private_multi_doc_dask_flighttask_inbound", jsonObject);
    }

    //机库增加属性
    private void addDockProperty(List<DockDTO> dockDTOList) {
        for (DockDTO dockDTO : dockDTOList) {
            Integer dockModeCode = djiBaseService.getDockModeCode(dockDTO.getDockSn());
            dockDTO.setDockMode(DockMode.getDescByCode(dockModeCode));
            dockDTO.setOnline(djiBaseService.isDockOnline(dockDTO.getDockSn()));
            String dockType = dockDTO.getDockType();
            if (BusinessConstant.MIAO_SUAN_SIGN.equals(dockType)) {
                List<SysDictDataEntity> list = dictDataDao.selectList(new QueryWrapper<SysDictDataEntity>()
                        .eq("dict_value", dockType).orderByAsc("create_date"));
                if (CollUtil.isNotEmpty(list)) {
                    dockDTO.setImgUrl(BusinessConstant.IMAGE_PATH + list.get(0).getImageUrl());
                }
            } else {
                String dockModel = dockDTO.getDockModel();
                List<SysDictDataEntity> list = dictDataDao.selectList(new QueryWrapper<SysDictDataEntity>()
                        .eq("dict_value", dockModel).orderByAsc("create_date"));
                if (CollUtil.isNotEmpty(list)) {
                    dockDTO.setImgUrl(BusinessConstant.IMAGE_PATH + list.get(0).getImageUrl());
                }
            }
        }
    }

}
