package com.fuyuanshen.equipment.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fuyuanshen.common.core.utils.MapstructUtils;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.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 com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceFenceTerminal;
import com.fuyuanshen.equipment.domain.DeviceGeoFence;
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo;
import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo;
import com.fuyuanshen.equipment.domain.bo.FenceTerminalBo;
import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse;
import com.fuyuanshen.equipment.domain.query.FenceCheckRequest;
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo;
import com.fuyuanshen.equipment.mapper.DeviceFenceTerminalMapper;
import com.fuyuanshen.equipment.mapper.DeviceGeoFenceMapper;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService;
import com.fuyuanshen.equipment.service.IDeviceFenceStatusService;
import com.fuyuanshen.equipment.service.IDeviceGeoFenceService;
import com.fuyuanshen.equipment.utils.map.GeoFenceChecker;
import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil;
import com.fuyuanshen.system.domain.SysRoleMenu;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 电子围栏Service业务层处理
 *
 * @author Lion Li
 * @date 2025-09-11
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class DeviceGeoFenceServiceImpl  extends ServiceImpl<DeviceGeoFenceMapper, DeviceGeoFence> implements IDeviceGeoFenceService {

    private final DeviceGeoFenceMapper baseMapper;

    private final IDeviceFenceStatusService fenceStatusService; // 添加此行
    
    private final IDeviceFenceAccessRecordService fenceAccessRecordService; // 添加此行
    private final DeviceFenceTerminalMapper deviceFenceTerminalMapper;



    /**
     * 查询电子围栏
     *
     * @param id 主键
     * @return 电子围栏
     */
    @Override
    public DeviceGeoFenceVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询电子围栏列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 电子围栏分页列表
     */
    @Override
    public TableDataInfo<DeviceGeoFenceVo> queryPageList(DeviceGeoFenceBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<DeviceGeoFence> lqw = buildQueryWrapper(bo);
        Page<DeviceGeoFenceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的电子围栏列表
     *
     * @param bo 查询条件
     * @return 电子围栏列表
     */
    @Override
    public List<DeviceGeoFenceVo> queryList(DeviceGeoFenceBo bo) {
        LambdaQueryWrapper<DeviceGeoFence> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<DeviceGeoFence> buildQueryWrapper(DeviceGeoFenceBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<DeviceGeoFence> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(DeviceGeoFence::getId);
        lqw.like(StringUtils.isNotBlank(bo.getName()), DeviceGeoFence::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), DeviceGeoFence::getDescription, bo.getDescription());
        lqw.eq(bo.getAreaType() != null, DeviceGeoFence::getAreaType, bo.getAreaType());
        lqw.eq(StringUtils.isNotBlank(bo.getCoordinates()), DeviceGeoFence::getCoordinates, bo.getCoordinates());
        lqw.eq(bo.getRadius() != null, DeviceGeoFence::getRadius, bo.getRadius());
        lqw.eq(bo.getIsActive() != null, DeviceGeoFence::getIsActive, bo.getIsActive());
        lqw.eq(bo.getCreateBy() != null, DeviceGeoFence::getCreateBy, bo.getCreateBy());
        lqw.eq(bo.getCreateTime() != null, DeviceGeoFence::getCreateTime, bo.getCreateTime());
        lqw.eq(bo.getUpdateTime() != null, DeviceGeoFence::getUpdateTime, bo.getUpdateTime());
        return lqw;
    }


    /**
     * 新增电子围栏
     *
     * @param bo 电子围栏
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(DeviceGeoFenceBo bo) {
        DeviceGeoFence add = MapstructUtils.convert(bo, DeviceGeoFence.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改电子围栏
     *
     * @param bo 电子围栏
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(DeviceGeoFenceBo bo) {
        DeviceGeoFence update = MapstructUtils.convert(bo, DeviceGeoFence.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

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

    /**
     * 校验并批量删除电子围栏信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }


    /**
     * 检查设备位置与围栏的关系
     *
     * @param request 位置检查请求
     * @return 位置检查结果
     */
    @Override
    public FenceCheckResponse checkPosition(FenceCheckRequest request) {
        // 1. 获取所有激活的围栏
        DeviceGeoFenceBo bo = new DeviceGeoFenceBo();
        bo.setIsActive(1L); // 假设1表示激活状态
        List<DeviceGeoFenceVo> activeFences = queryList(bo);

        // 2. 初始化响应对象
        FenceCheckResponse response = new FenceCheckResponse();
        response.setDeviceId(request.getDeviceId());
        response.setCheckTime(System.currentTimeMillis());
        response.setEnteredFences(new ArrayList<>());
        response.setExitedFences(new ArrayList<>());
        response.setCurrentFences(new ArrayList<>());

        // 3. 遍历所有激活的围栏
        for (DeviceGeoFenceVo fence : activeFences) {
            // 解析围栏坐标
            ObjectMapper objectMapper = new ObjectMapper();
            List<GeoFenceChecker.Coordinate> coordinateList = new ArrayList<>();
            try {
                coordinateList = objectMapper.readValue(fence.getCoordinates(),
                        new TypeReference<List<GeoFenceChecker.Coordinate>>() {
                        });
            } catch (Exception e) {
                log.error("坐标数据解析失败: {}", e.getMessage());
                continue; // 解析失败则跳过该围栏
            }

            // 检查设备是否在围栏内
            boolean pointInFence = GeoFenceChecker.isPointInFence(
                    request.getLatitude(),
                    request.getLongitude(),
                    fence.getAreaType(),
                    coordinateList,
                    fence.getRadius());

            // 创建围栏信息对象
            FenceCheckResponse.FenceInfo fenceInfo = new FenceCheckResponse.FenceInfo();
            fenceInfo.setFenceId(fence.getId());
            fenceInfo.setFenceName(fence.getName());
            fenceInfo.setFenceType(fence.getAreaType());

            // // 查询设备在该围栏的历史状态
            // DeviceFenceStatusBo statusQuery = new DeviceFenceStatusBo();
            // statusQuery.setDeviceId(request.getDeviceId());
            // statusQuery.setFenceId(fence.getId());
            // List<DeviceFenceStatusVo> statusHistory = fenceStatusService.queryList(statusQuery);
            //
            // // 获取最新的状态记录
            // DeviceFenceStatusVo latestStatus = statusHistory.stream()
            //         .max(Comparator.comparing(DeviceFenceStatusVo::getLastCheckTime))
            //         .orElse(null);

            // 查询设备在该围栏的最新状态
            DeviceFenceStatusVo latestStatus = fenceStatusService.getLatestStatusByDeviceAndFence(
                    request.getDeviceId(), fence.getId());

            // 判断设备与围栏的关系变化 1=进入围栏,2=离开围栏
            Long previousStatus = latestStatus != null ? latestStatus.getStatus() : 2L; // 默认在围栏外
            Long currentStatus = pointInFence ? 1L : 2L; // 当前状态：1-在围栏内，2-在围栏外

            // 如果状态发生变化，则记录
            if (!previousStatus.equals(currentStatus)) {
                // 创建新的状态记录
                DeviceFenceStatusBo newStatus = new DeviceFenceStatusBo();
                newStatus.setDeviceId(request.getDeviceId());
                newStatus.setFenceId(fence.getId());
                newStatus.setStatus(currentStatus);
                newStatus.setLastCheckTime(new Date());

                // 保存状态记录
                fenceStatusService.insertByBo(newStatus);

                // 添加围栏进出记录
                DeviceFenceAccessRecordBo recordBo = new DeviceFenceAccessRecordBo();
                recordBo.setDeviceId(request.getDeviceId());
                recordBo.setFenceId(fence.getId());
                recordBo.setLatitude(request.getLatitude());
                recordBo.setLongitude(request.getLongitude());
                String address = GetAddressFromLatUtil.getAdd(request.getLongitude().toString(), request.getLatitude().toString());
                recordBo.setEventAddress(address);

                recordBo.setEventTime(new Date());
                // 1表示进入围栏，2表示离开围栏
                recordBo.setEventType(currentStatus);
                fenceAccessRecordService.insertByBo(recordBo);

                // 根据状态变化更新响应
                if (currentStatus == 1L) {
                    // 设备进入围栏
                    response.getEnteredFences().add(fenceInfo);
                } else {
                    // 设备离开围栏
                    response.getExitedFences().add(fenceInfo);
                }
            } else if (currentStatus == 1L) {
                // 状态未变，但设备仍在围栏内
                response.getCurrentFences().add(fenceInfo);
            }
        }

        return response;
    }


    @Override
    public Boolean addFenceTerminal(FenceTerminalBo bo) {
        // 新增围栏与终端关联信息
        List<DeviceFenceTerminal> list = new ArrayList<>();
        for (Long deviceId : bo.getDeviceIds()) {
            DeviceFenceTerminal rm = new DeviceFenceTerminal();
            rm.setFenceId(bo.getFenceId());
            rm.setDeviceId(deviceId);
            list.add(rm);
        }
        if (!list.isEmpty()) {
            return deviceFenceTerminalMapper.insertBatch(list);
        }
        return false;
    }

    @Override
    public Boolean delFenceTerminal(FenceTerminalBo bo) {
        if (bo.getFenceId() == null || bo.getDeviceIds() == null || bo.getDeviceIds().isEmpty()) {
            throw new IllegalArgumentException("围栏ID或设备ID不能为空");
        }
        LambdaUpdateWrapper<DeviceFenceTerminal> lambda = new LambdaUpdateWrapper<DeviceFenceTerminal>()
                .eq(DeviceFenceTerminal::getFenceId, bo.getFenceId())
                .in(DeviceFenceTerminal::getDeviceId, bo.getDeviceIds());
        return deviceFenceTerminalMapper.delete(lambda) > 0;
    }


}