package com.sz.admin.monitor.service.impl;

import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.sz.admin.monitor.mapper.AlgorithmTaskMapper;
import com.sz.admin.monitor.mapper.CameraMapper;
import com.sz.admin.monitor.mapper.EdgeBoxMapper;
import com.sz.admin.monitor.mapper.NvrMapper;
import com.sz.admin.monitor.pojo.dto.edgebox.*;
import com.sz.admin.monitor.pojo.po.AlgorithmTask;
import com.sz.admin.monitor.pojo.po.Camera;
import com.sz.admin.monitor.pojo.po.EdgeBox;
import com.sz.admin.monitor.pojo.po.Nvr;
import com.sz.admin.monitor.pojo.vo.edgebox.EdgeBoxVO;
import com.sz.admin.monitor.service.EdgeBoxService;
import com.sz.admin.monitor.utils.AiBoxRequestUtil;
import com.sz.admin.monitor.utils.RtspUtil;
import com.sz.core.common.exception.common.BusinessException;
import com.sz.platform.enums.AdminResponseEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.query.QueryChain;
import com.sz.core.common.enums.CommonResponseEnum;
import com.sz.core.util.PageUtils;
import com.sz.core.util.BeanCopyUtils;
import com.sz.core.util.Utils;
import com.sz.core.common.entity.PageResult;
import com.sz.core.common.entity.SelectIdsDTO;

import java.io.Serializable;
import java.util.List;

import com.sz.core.common.entity.ImportExcelDTO;
import com.sz.excel.core.ExcelResult;

import java.io.OutputStream;
import java.util.Map;
import java.util.stream.Collectors;

import jakarta.servlet.http.HttpServletResponse;
import com.sz.core.util.FileUtils;
import com.sz.excel.utils.ExcelUtils;
import lombok.SneakyThrows;
import com.sz.core.datascope.SimpleDataScopeHelper;
import org.springframework.transaction.annotation.Transactional;


/**
 * <p>
 * 边缘盒子 服务实现类
 * </p>
 *
 * @author Lz
 * @since 2026-03-05
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class EdgeBoxServiceImpl extends ServiceImpl<EdgeBoxMapper, EdgeBox> implements EdgeBoxService {
    private final CameraMapper cameraMapper;
    private final AiBoxRequestUtil aiBoxRequestUtil;
    private final NvrMapper nvrMapper;
    private final AlgorithmTaskMapper algorithmTaskMapper;

    @Override
    public void create(EdgeBoxCreateDTO dto) {
        EdgeBox ryEdgeBox = BeanCopyUtils.copy(dto, EdgeBox.class);
        long count;
        // 唯一性校验
        count = QueryChain.of(EdgeBox.class).eq(EdgeBox::getIp, dto.getIp()).count();
        CommonResponseEnum.EXISTS.message("ip已存在").assertTrue(count > 0);
        save(ryEdgeBox);
    }

    @Override
    public void update(EdgeBoxUpdateDTO dto) {
        EdgeBox ryEdgeBox = BeanCopyUtils.copy(dto, EdgeBox.class);
        QueryWrapper wrapper;
        // id有效性校验
        wrapper = QueryWrapper.create()
            .eq(EdgeBox::getId, dto.getId());
        CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0);

        // 唯一性校验
        long count;
        count = QueryChain.of(EdgeBox.class).eq(EdgeBox::getIp, dto.getIp()).ne(EdgeBox::getId, dto.getId()).count();
        CommonResponseEnum.EXISTS.message("ip已存在").assertTrue(count > 0);
        saveOrUpdate(ryEdgeBox);
    }

    @Override
    public PageResult<EdgeBoxVO> page(EdgeBoxListDTO dto) {
        try {
            SimpleDataScopeHelper.start(EdgeBox.class);
            Page<EdgeBoxVO> page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), EdgeBoxVO.class);
            return PageUtils.getPageResult(page);
        } finally {
            SimpleDataScopeHelper.clearDataScope();
        }
    }

    @Override
    public List<EdgeBoxVO> list(EdgeBoxListDTO dto) {
        try {
            SimpleDataScopeHelper.start(EdgeBox.class);
            return listAs(buildQueryWrapper(dto), EdgeBoxVO.class);
        } finally {
            SimpleDataScopeHelper.clearDataScope();
        }
    }

    @Override
    public void remove(SelectIdsDTO dto) {
        CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty());
        removeByIds(dto.getIds());
    }

    @Override
    public EdgeBoxVO detail(Object id) {
        EdgeBox ryEdgeBox = getById((Serializable) id);
        CommonResponseEnum.INVALID_ID.assertNull(ryEdgeBox);
        return BeanCopyUtils.copy(ryEdgeBox, EdgeBoxVO.class);
    }

    @SneakyThrows
    @Override
    public void importExcel(ImportExcelDTO dto) {
        ExcelResult<EdgeBoxImportDTO> excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), EdgeBoxImportDTO.class, true);
        List<EdgeBoxImportDTO> list = excelResult.getList();
        // 入库
        List<EdgeBox> importList = BeanCopyUtils.copyList(list, EdgeBox.class);
        saveBatch(importList);
        List<String> errorList = excelResult.getErrorList();
        String analysis = excelResult.getAnalysis();
        System.out.println(" analysis : " + analysis);
        System.out.println(" isCover : " + dto.getIsCover());
    }

    @SneakyThrows
    @Override
    public void exportExcel(EdgeBoxListDTO dto, HttpServletResponse response) {
        List<EdgeBoxVO> list = list(dto);
        String fileName = "边缘盒子模板";
        OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx");
        ExcelUtils.exportExcel(list, "边缘盒子", EdgeBoxVO.class, os);
    }

    @Override
    @Transactional
    public void bindCameras(EdgeBoxBindCamerasDTO dto) {
        List<Long> cameraIds = dto.getCameraIds();
        Long boxId = dto.getBoxId();
        if (cameraIds.size() > 16) {
            throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "绑定的摄像头数量不能超过16个");
        }
        // 找出新增和被移除的通道
        List<Long> oldCameraIds = cameraMapper.selectIdsByEdgeBoxId(boxId);
        // 找出新增的通道
        List<Long> addedIds = cameraIds.stream().filter(id -> !oldCameraIds.contains(id)).toList();
        // 找出被移除的通道
        List<Long> removeIds = oldCameraIds.stream().filter(id -> !cameraIds.contains(id)).toList();
        if (!addedIds.isEmpty()) {
            // 批量更新
            cameraMapper.updateBoxIdForCameras(boxId, addedIds);
        }
        if (!removeIds.isEmpty()) {
            cameraMapper.updateBoxIdForCameras(null, removeIds);
        }
        // 调用盒子接口
        try {
            if (!addedIds.isEmpty()) {
                // 注册新通道
                EdgeBox box = this.getById(boxId);
                for (Long addedId : addedIds) {
                    SetupChannelDTO channelDTO = new SetupChannelDTO();
                    channelDTO.setMediaName(addedId.toString());
                    Camera camera = cameraMapper.selectOneById(addedId);
                    Nvr nvr = nvrMapper.selectOneById(camera.getNvrId());
                    Map<String, String> rtsp = RtspUtil.getRtsp(nvr.getDriver(), nvr.getAccount(), nvr.getPassword(), camera.getChannelId() - 32, nvr.getIp(), 554);
                    channelDTO.setMediaUrl(rtsp.get("mainRtsp"));
                    channelDTO.setMediaDesc(camera.getName() + ":" + camera.getIpAddress());
                    aiBoxRequestUtil.setupVideoChannel(box.getIp(), box.getPort(), channelDTO);
                }
            }
            if (!removeIds.isEmpty()) {
                // 删除被移出的通道
                EdgeBox box = this.getById(boxId);
                for (Long removeId : removeIds) {
                    // TODO 如果该通道配置了算法，则需要关闭和删除任务再进行一个删除通道
                    AlgorithmTask algorithmTask = algorithmTaskMapper.selectByCameraId(removeId);
                    if (algorithmTask != null)
                    {
                        algorithmTaskMapper.delete(algorithmTask);
                        aiBoxRequestUtil.controlTask(box.getIp(), box.getPort(), algorithmTask.getAlgTaskSession(), 0);
                        aiBoxRequestUtil.deleteTask(box.getIp(), box.getPort(), algorithmTask.getAlgTaskSession());
                        aiBoxRequestUtil.deleteVideoChannel(box.getIp(), box.getPort(), removeId.toString());
                    }else {
                        aiBoxRequestUtil.deleteVideoChannel(box.getIp(), box.getPort(), removeId.toString());
                    }

                }
            }
        } catch (Exception e) {
            log.error("同步边缘盒子失败", e);
            throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "边缘计算盒子同步失败，已撤销绑定操作。请检查盒子网络！");
        }
    }

    private static QueryWrapper buildQueryWrapper(EdgeBoxListDTO dto) {
        QueryWrapper wrapper = QueryWrapper.create().from(EdgeBox.class);
        if (Utils.isNotNull(dto.getName())) {
            wrapper.like(EdgeBox::getName, dto.getName());
        }
        if (Utils.isNotNull(dto.getIp())) {
            wrapper.eq(EdgeBox::getIp, dto.getIp());
        }
        if (Utils.isNotNull(dto.getPort())) {
            wrapper.eq(EdgeBox::getPort, dto.getPort());
        }
        if (Utils.isNotNull(dto.getMask())) {
            wrapper.eq(EdgeBox::getMask, dto.getMask());
        }
        if (Utils.isNotNull(dto.getGateway())) {
            wrapper.eq(EdgeBox::getGateway, dto.getGateway());
        }
        if (Utils.isNotNull(dto.getAccount())) {
            wrapper.eq(EdgeBox::getAccount, dto.getAccount());
        }
        if (Utils.isNotNull(dto.getPassword())) {
            wrapper.eq(EdgeBox::getPassword, dto.getPassword());
        }
        return wrapper;
    }
}