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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.hutool.core.util.StrUtil;
import com.multictrl.common.constant.BusinessConstant;
import com.multictrl.common.exception.ErrorCode;
import com.multictrl.common.page.PageData;
import com.multictrl.common.service.impl.CrudServiceImpl;
import com.multictrl.common.utils.ConvertUtils;
import com.multictrl.common.utils.kmz.KmzUtils;
import com.multictrl.common.validator.AssertUtils;
import com.multictrl.modules.business.dao.RouteDao;
import com.multictrl.modules.business.dao.RouteWaypointDao;
import com.multictrl.modules.business.dao.WaypointActionDao;
import com.multictrl.modules.business.dto.RouteDTO;
import com.multictrl.modules.business.dto.RouteWaypointDTO;
import com.multictrl.modules.business.dto.WaypointActionDTO;
import com.multictrl.modules.business.entity.RouteEntity;
import com.multictrl.modules.business.entity.RouteWaypointEntity;
import com.multictrl.modules.business.entity.WaypointActionEntity;
import com.multictrl.modules.business.service.MinioService;
import com.multictrl.modules.business.service.RouteService;
import com.multictrl.modules.security.user.SecurityUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 航线信息表
 *
 * @author Sdy
 * @since 1.0.0 2026-04-20
 */
@RequiredArgsConstructor
@Service
public class RouteServiceImpl extends CrudServiceImpl<RouteDao, RouteEntity, RouteDTO> implements RouteService {
    private final RouteWaypointDao routeWaypointDao;
    private final WaypointActionDao waypointActionDao;
    private final MinioService minioService;

    @Override
    public QueryWrapper<RouteEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");
        String routeName = (String) params.get("routeName");
        String dockSn = (String) params.get("dockSn");

        QueryWrapper<RouteEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(id), "id", id);
        wrapper.like(StrUtil.isNotBlank(routeName), "route_name", routeName);
        wrapper.eq(StrUtil.isNotBlank(dockSn), "dock_sn", dockSn);
        wrapper.orderByDesc("update_date");

        return wrapper;
    }

    @Override
    public PageData<RouteDTO> pageList(Map<String, Object> params) {
        PageData<RouteDTO> page = page(params);
        for (RouteDTO dto : page.getList()) {
            if (StrUtil.isNotBlank(dto.getImgUrl())) {
                dto.setImgUrl(BusinessConstant.IMAGE_PATH + dto.getImgUrl());
            }
        }
        return page;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveRoute(RouteDTO routeDTO) {
        //判断航线名称是否已存在
        checkRouteExist(null, routeDTO.getRouteName());
        List<RouteWaypointDTO> routeWaypointList = routeDTO.getRouteWaypointList();

        //航点动作处理
        handleWaypointAction(routeWaypointList);

        //保存信息
        String kmzUrl = generateKml(routeDTO);
        RouteEntity routeEntity = ConvertUtils.sourceToTarget(routeDTO, currentModelClass());
        routeEntity.setKmzUrl(kmzUrl);
        routeEntity.setDeptId(SecurityUser.getDeptId());
        routeEntity.setWaypointNum(routeWaypointList.size());
        String imgUrl = routeDTO.getImgUrl();
        routeEntity.setImgUrl(imgUrl.replaceAll(BusinessConstant.IMAGE_PATH, ""));
        baseDao.insert(routeEntity);

        //保存航点信息
        saveWaypoint(routeEntity.getId(), routeWaypointList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateRoute(RouteDTO routeDTO) {
        Long routeId = routeDTO.getId();
        //判断航线名称是否已存在
        checkRouteExist(routeId, routeDTO.getRouteName());
        List<RouteWaypointDTO> routeWaypointList = routeDTO.getRouteWaypointList();

        //航点动作处理
        handleWaypointAction(routeWaypointList);

        //修改信息
        String kmzUrl = generateKml(routeDTO);
        RouteEntity routeEntity = ConvertUtils.sourceToTarget(routeDTO, currentModelClass());
        routeEntity.setKmzUrl(kmzUrl);
        //航线创建时的部门，修改时不会改变
        RouteEntity entity = selectById(routeId);
        routeEntity.setDeptId(entity.getDeptId());
        routeEntity.setWaypointNum(routeWaypointList.size());
        String imgUrl = routeDTO.getImgUrl();
        routeEntity.setImgUrl(imgUrl.replaceAll(BusinessConstant.IMAGE_PATH, ""));
        updateById(routeEntity);

        //删除历史航点及航点动作
        routeWaypointDao.delete(new QueryWrapper<RouteWaypointEntity>().eq("route_id", routeId));
        waypointActionDao.delete(new QueryWrapper<WaypointActionEntity>().eq("route_id", routeId));
        //保存航点信息
        saveWaypoint(routeId, routeWaypointList);

        //删除kmz
        if (StrUtil.isNotBlank(entity.getKmzUrl())) {
            minioService.removeFile(BusinessConstant.ROUTE_KMZ_BUCKET, entity.getKmzUrl().replaceAll(BusinessConstant.ROUTE_KMZ_BUCKET, ""));
        }
    }

    @Override
    public RouteDTO getRoute(Long id) {
        RouteDTO routeDTO = ConvertUtils.sourceToTarget(selectById(id), RouteDTO.class);
        //航点信息
        List<RouteWaypointEntity> routeWaypointList = routeWaypointDao.selectList(new QueryWrapper<RouteWaypointEntity>()
                .eq("route_id", id).orderByAsc("waypoint_sort"));
        List<RouteWaypointDTO> routeWaypointDTOList = ConvertUtils.sourceToTarget(routeWaypointList, RouteWaypointDTO.class);
        for (RouteWaypointDTO waypoint : routeWaypointDTOList) {
            //航点动作
            List<WaypointActionEntity> actionEntities = waypointActionDao.selectList(new QueryWrapper<WaypointActionEntity>()
                    .eq("route_id", id).eq("waypoint_id", waypoint.getId()).orderByAsc("action_sort"));
            List<WaypointActionDTO> actionDTOList = ConvertUtils.sourceToTarget(actionEntities, WaypointActionDTO.class);
            waypoint.setWaypointActionList(actionDTOList);
        }

        routeDTO.setRouteWaypointList(routeWaypointDTOList);
        return routeDTO;
    }

    @Override
    public String generateKml(RouteDTO routeDTO) {
        try {
            byte[] bytes = KmzUtils.generateKmzBytes(routeDTO);
            return minioService.uploadRouteKmz(routeDTO.getDockSn(), bytes);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //判断航线是否存在
    private void checkRouteExist(Long id, String routeName) {
        RouteEntity uavRouteEntity = baseDao.selectOne(new QueryWrapper<RouteEntity>()
                .eq("route_name", routeName)
                .ne(id != null, "id", id));
        AssertUtils.noNull(uavRouteEntity, ErrorCode.ROUTE_EXIST);
    }

    //保存航点信息
    private void saveWaypoint(Long routeId, List<RouteWaypointDTO> waypointList) {
        for (int i = 0; i < waypointList.size(); i++) {
            RouteWaypointDTO uavWaypointDTO = waypointList.get(i);
            RouteWaypointEntity waypointEntity = ConvertUtils.sourceToTarget(uavWaypointDTO, RouteWaypointEntity.class);
            waypointEntity.setRouteId(routeId);
            waypointEntity.setWaypointSort(i);
            routeWaypointDao.insert(waypointEntity);

            //航点动作
            List<WaypointActionEntity> actionEntities = ConvertUtils.sourceToTarget(uavWaypointDTO.getWaypointActionList(), WaypointActionEntity.class);
            for (int y = 0; y < actionEntities.size(); y++) {
                WaypointActionEntity actionEntity = actionEntities.get(y);
                actionEntity.setWaypointId(waypointEntity.getId());
                actionEntity.setActionSort(y);
                actionEntity.setRouteId(routeId);
                waypointActionDao.insert(actionEntity);
            }
        }
    }

    /**
     * 航点动作处理
     * 开始录像后 在结束录像前不能有拍照 如果有将拍照删掉
     * 等时/等距拍照开始后 在结束拍照前 中间不能有其他的等时/等距拍照 如果有将其移除
     */
    private void handleWaypointAction(List<RouteWaypointDTO> waypointList) {
        if (waypointList == null || waypointList.isEmpty()) {
            return;
        }

        // Step 1: 收集所有动作，并记录它们来自哪个航点
        List<WaypointActionDTO> allActions = new ArrayList<>();
        List<Integer> actionToWaypointIndex = new ArrayList<>();

        for (int i = 0; i < waypointList.size(); i++) {
            RouteWaypointDTO waypoint = waypointList.get(i);
            List<WaypointActionDTO> actions = waypoint.getWaypointActionList();
            if (actions != null) {
                for (WaypointActionDTO action : actions) {
                    if (BusinessConstant.FINISH_TAKE_PHOTO_FLAG.equals(action.getActionType())) {
                        action.setActionValue(StrUtil.toString(i));
                    }
                    allActions.add(action);
                    actionToWaypointIndex.add(i); // 记录该动作属于第几个航点
                }
            }
        }

        // Step 2: 全局遍历并过滤动作
        boolean isRecordingVideo = false;
        boolean currentPhotoType = false;

        // 存储过滤后的结果（按原顺序）
        List<List<WaypointActionDTO>> filteredActionsByWaypoint = new ArrayList<>();
        for (int i = 0; i < waypointList.size(); i++) {
            filteredActionsByWaypoint.add(new ArrayList<>());
        }

        for (int i = 0; i < allActions.size(); i++) {
            WaypointActionDTO action = allActions.get(i);
            String actionType = action.getActionType();

            // 处理录像状态
            if (BusinessConstant.START_VIDEO_FLAG.equals(actionType)) {
                if (isRecordingVideo) {
                    continue; //已经开始录像
                } else {
                    isRecordingVideo = true;
                    int waypointIndex = actionToWaypointIndex.get(i);
                    filteredActionsByWaypoint.get(waypointIndex).add(action);
                }
                continue;
            }

            if (BusinessConstant.STOP_VIDEO_FLAG.equals(actionType)) {
                if (isRecordingVideo) {
                    isRecordingVideo = false;
                    int waypointIndex = actionToWaypointIndex.get(i);
                    filteredActionsByWaypoint.get(waypointIndex).add(action);
                }
                continue;
            }

            // 录像过程中禁止特定类型的动作
            if (isRecordingVideo && isTakePhotoFlag(actionType)) {
                continue; // 跳过被限制的动作
            }

            // 处理等时/等距拍照开始
            if (BusinessConstant.EQUAL_TIME_TAKE_PHOTO_FLAG.equals(actionType) || BusinessConstant.EQUAL_DISTANCE_TAKE_PHOTO_FLAG.equals(actionType)) {
                if (currentPhotoType) {
                    continue; // 已经在等时拍照中，跳过重复开始
                } else {
                    currentPhotoType = true;
                    int waypointIndex = actionToWaypointIndex.get(i);
                    filteredActionsByWaypoint.get(waypointIndex).add(action);
                }
                continue;
            }

            // 处理等时/等距拍照结束
            if (BusinessConstant.FINISH_TAKE_PHOTO_FLAG.equals(actionType)) {
                if (currentPhotoType) {
                    int waypointIndex = actionToWaypointIndex.get(i);
                    filteredActionsByWaypoint.get(waypointIndex).add(action);
                    currentPhotoType = false;
                }
                continue;
            }

            // 默认情况：其他动作保留
            int waypointIndex = actionToWaypointIndex.get(i);
            filteredActionsByWaypoint.get(waypointIndex).add(action);
        }

        // Step 3: 检查并清理未配对的拍照动作
        for (int jj = 0; jj < filteredActionsByWaypoint.size(); jj++) {
            List<WaypointActionDTO> actions = filteredActionsByWaypoint.get(jj);
            for (int i = 0; i < actions.size(); i++) {
                WaypointActionDTO action = actions.get(i);
                String actionType = action.getActionType();

                if (BusinessConstant.EQUAL_TIME_TAKE_PHOTO_FLAG.equals(actionType) || BusinessConstant.EQUAL_DISTANCE_TAKE_PHOTO_FLAG.equals(actionType)) {
                    boolean foundFinish = false;
                    for (int j = i + 1; j < actions.size(); j++) {
                        WaypointActionDTO nextAction = actions.get(j);
                        if (BusinessConstant.FINISH_TAKE_PHOTO_FLAG.equals(nextAction.getActionType())) {
                            foundFinish = true;
                            break;
                        }
                    }
                    //继续往下寻找
                    for (int ii = jj + 1; ii < filteredActionsByWaypoint.size(); ii++) {
                        List<WaypointActionDTO> actionss = filteredActionsByWaypoint.get(ii);
                        for (WaypointActionDTO nextAction : actionss) {
                            if (BusinessConstant.FINISH_TAKE_PHOTO_FLAG.equals(nextAction.getActionType())) {
                                foundFinish = true;
                                break;
                            }
                        }
                    }
                    if (!foundFinish) {
                        actions.remove(i);
                        i--;
                    }
                }
            }
        }

        // Step 4: 更新航点动作列表
        for (int i = 0; i < waypointList.size(); i++) {
            waypointList.get(i).setWaypointActionList(filteredActionsByWaypoint.get(i));
        }
    }

    private boolean isTakePhotoFlag(String actionType) {
        return BusinessConstant.TAKE_PHOTO_FLAG.equals(actionType) ||
                BusinessConstant.EQUAL_TIME_TAKE_PHOTO_FLAG.equals(actionType) ||
                BusinessConstant.EQUAL_DISTANCE_TAKE_PHOTO_FLAG.equals(actionType);
    }
}