package com.yupi.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.project.common.ErrorCode;
import com.yupi.project.exception.BusinessException;
import com.yupi.project.mapper.ChargingRobotMapper;
import com.yupi.project.model.entity.ChargingRobot;
import com.yupi.project.model.entity.ParkingSpot;
import com.yupi.project.model.entity.RobotTask;
import com.yupi.project.model.enums.ParkingSpotStatusEnum;
import com.yupi.project.model.enums.RobotStatusEnum;
import com.yupi.project.service.ChargingRobotService;
import com.yupi.project.service.ParkingSpotService;
import com.yupi.project.service.RobotTaskService;
import com.yupi.project.service.ChargingSessionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
* @author Yupi
* @description 针对表【charging_robot(充电机器人表)】的数据库操作Service实现
* @createDate 2023-12-03 10:00:00
*/
@Service
@Slf4j
public class ChargingRobotServiceImpl extends ServiceImpl<ChargingRobotMapper, ChargingRobot>
    implements ChargingRobotService {

    private final ParkingSpotService parkingSpotService;
    private final RobotTaskService robotTaskService;
    private final ChargingSessionService chargingSessionService;

    @Autowired
    public ChargingRobotServiceImpl(ParkingSpotService parkingSpotService, 
                                    RobotTaskService robotTaskService, 
                                    @Lazy ChargingSessionService chargingSessionService) {
        this.parkingSpotService = parkingSpotService;
        this.robotTaskService = robotTaskService;
        this.chargingSessionService = chargingSessionService;
    }

    @Override
    @Transactional
    public ChargingRobot registerRobot(String robotUid, RobotStatusEnum initialStatus) {
        if (findByRobotUid(robotUid) != null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "机器人UID已存在: " + robotUid);
        }
        ChargingRobot robot = new ChargingRobot();
        robot.setRobotUid(robotUid);
        robot.setStatus(initialStatus.getValue());
        robot.setCreateTime(new Date());
        robot.setUpdateTime(new Date());
        boolean saved = this.save(robot);
        if (!saved) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "机器人注册失败");
        }
        log.info("机器人注册成功: {}", robot);
        return robot;
    }

    @Override
    public ChargingRobot findByRobotUid(String robotUid) {
        QueryWrapper<ChargingRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("robot_uid", robotUid);
        return this.getOne(queryWrapper);
    }

    @Override
    @Transactional
    public boolean updateRobotStatus(String robotUID, RobotStatusEnum status, String location, 
                                     Integer batteryLevel, Long currentTaskId, Date lastHeartbeatTime) {
        if (StringUtils.isBlank(robotUID)) {
            log.warn("更新机器人状态失败：robotUID 为空。");
            return false;
        }

        ChargingRobot robot = this.findByRobotUid(robotUID);
        if (robot == null) {
            log.warn("更新机器人状态失败：未找到 UID 为 {} 的机器人。", robotUID);
            return false;
        }

        ChargingRobot robotToUpdate = new ChargingRobot();
        robotToUpdate.setId(robot.getId());
        boolean changed = false;

        RobotStatusEnum oldStatus = RobotStatusEnum.getEnumByValue(robot.getStatus());
        
        if (status == RobotStatusEnum.CHARGING && oldStatus != RobotStatusEnum.CHARGING) {
            if (currentTaskId != null) {
                RobotTask task = robotTaskService.getById(currentTaskId);
                if (task != null && task.getRelatedSessionId() != null) {
                    log.info("机器人 {} 状态变更为 CHARGING，触发会话 {} 的到达/充电开始逻辑。", robotUID, task.getRelatedSessionId());
                    chargingSessionService.handleRobotArrival(task.getRelatedSessionId(), currentTaskId);
                } else {
                    log.warn("机器人 {} 状态变为 CHARGING，但找不到关联的任务或任务未关联会话。TaskId: {}", robotUID, currentTaskId);
                }
            } else {
                log.warn("机器人 {} 状态变为 CHARGING，但上报信息中缺少 currentTaskId，无法推进业务流程。", robotUID);
            }
        }
        
        if (oldStatus == RobotStatusEnum.CHARGING && status != RobotStatusEnum.CHARGING) {
            if (StringUtils.isNotBlank(robot.getCurrentLocation())) {
                ParkingSpot spotToRelease = parkingSpotService.findBySpotUid(robot.getCurrentLocation());
                if (spotToRelease != null && spotToRelease.getStatus().equals(ParkingSpotStatusEnum.CHARGING.getValue())) {
                    log.info("机器人 {} 停止充电，释放车位 {}", robotUID, robot.getCurrentLocation());
                    parkingSpotService.releaseSpot(spotToRelease.getId());
                }
            }
        }

        if (status != null && !status.getValue().equals(robot.getStatus())) {
            robotToUpdate.setStatus(status.getValue());
            changed = true;
        }

        if (location != null && !location.equals(robot.getCurrentLocation())) {
            robotToUpdate.setCurrentLocation(location);
            changed = true;
        }

        if (batteryLevel != null && !batteryLevel.equals(robot.getBatteryLevel())) {
            robotToUpdate.setBatteryLevel(batteryLevel);
            changed = true;
        }

        if (currentTaskId != null && !currentTaskId.equals(robot.getCurrentTaskId())) {
            robotToUpdate.setCurrentTaskId(currentTaskId);
            changed = true;
        }
        
        if (lastHeartbeatTime != null && (robot.getLastHeartbeatTime() == null || !lastHeartbeatTime.equals(robot.getLastHeartbeatTime()))){
            robotToUpdate.setLastHeartbeatTime(lastHeartbeatTime);
            changed = true;
        }

        if (!changed) {
            if(status == oldStatus){
                 log.info("机器人 {} 的状态与数据库一致 (状态: {}, 位置: {}, 电量: {}, 任务ID: {}, 心跳: {})，无需更新。",
                    robotUID, status, location, batteryLevel, currentTaskId, lastHeartbeatTime);
            }
            return true; 
        }

        boolean success = this.updateById(robotToUpdate);
        if (success) {
            log.info("成功更新机器人 {} 的状态。新状态: {}, 位置: {}, 电量: {}, 当前任务ID: {}, 心跳: {}", 
                    robotUID, status, location, batteryLevel, currentTaskId, lastHeartbeatTime);
        } else {
            log.error("更新机器人 {} 的状态失败 (数据库操作失败)。", robotUID);
        }
        return success;
    }

    @Override
    public boolean updateBatteryLevel(Long robotId, Integer batteryLevel) {
        ChargingRobot robot = this.getById(robotId);
        if (robot == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "机器人不存在");
        }
        if (batteryLevel < 0 || batteryLevel > 100) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "无效的电池电量值");
        }
        robot.setBatteryLevel(batteryLevel);
        robot.setUpdateTime(new Date());
        return this.updateById(robot);
    }

    @Override
    public boolean updateHeartbeatTime(Long robotId, Date heartbeatTime) {
        ChargingRobot robot = this.getById(robotId);
        if (robot == null) {
            // 心跳通常来自已注册机器人，如果找不到可以只记录日志不抛异常，或根据策略决定
            log.warn("尝试更新心跳失败，机器人不存在: {}", robotId);
            return false;
        }
        robot.setLastHeartbeatTime(heartbeatTime);
        robot.setUpdateTime(new Date()); // 可选，心跳更新是否算作整体记录更新
        return this.updateById(robot);
    }

    @Override
    public List<ChargingRobot> findRobotsByStatus(RobotStatusEnum status) {
        QueryWrapper<ChargingRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", status.getValue());
        return this.list(queryWrapper);
    }

    @Override
    @Transactional // 确保原子性
    public ChargingRobot assignIdleRobot() {
        // 简单策略：查找第一个空闲的机器人并尝试锁定
        // 后续可优化：考虑负载均衡、机器人位置、电量等因素
        QueryWrapper<ChargingRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", RobotStatusEnum.IDLE.getValue())
                    .orderByAsc("update_time") // 尝试获取最近更新为空闲的，或根据其他策略排序
                    .last("FOR UPDATE"); // 行级锁，防止并发问题

        List<ChargingRobot> idleRobots = this.list(queryWrapper);
        if (idleRobots.isEmpty()) {
            log.warn("没有可用的空闲机器人");
            return null;
        }

        ChargingRobot assignedRobot = idleRobots.get(0); // 取第一个
        // 更新机器人状态为MOVING或ASSIGNED，并关联任务（如果此时有任务ID）
        // 这里暂时只更新为MOVING，具体任务ID关联由调用方处理
        boolean success = updateRobotStatus(assignedRobot.getRobotUid(), RobotStatusEnum.MOVING, null, null, null, null);
        if (success) {
            log.info("成功分配机器人: {} (ID: {})", assignedRobot.getRobotUid(), assignedRobot.getId());
            return assignedRobot;
        } else {
            log.error("分配机器人 {} 失败，未能更新其状态", assignedRobot.getRobotUid());
            // 可能需要重试或选择其他机器人
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "分配机器人失败，无法更新状态");
        }
    }

    @Override
    @Transactional
    public boolean releaseRobot(Long robotId) {
        ChargingRobot robot = getById(robotId);
        if (robot == null) {
            log.warn("尝试释放机器人失败，机器人不存在: {}", robotId);
            return false;
        }

        // 关键修复：确保释放机器人时，原子性地更新其状态和任务ID
        ChargingRobot robotToUpdate = new ChargingRobot();
        robotToUpdate.setId(robotId);
        robotToUpdate.setStatus(RobotStatusEnum.IDLE.getValue());
        robotToUpdate.setCurrentTaskId(null); // 显式清除任务ID

        boolean success = this.updateById(robotToUpdate);
        if (success) {
            log.info("成功释放机器人 {}，状态设置为IDLE，任务ID已清除。", robot.getRobotUid());
        } else {
            log.error("数据库操作失败，未能释放机器人 {}", robot.getRobotUid());
        }
        return success;
    }

    @Override
    public long countOnlineRobots() {
        QueryWrapper<ChargingRobot> queryWrapper = new QueryWrapper<>();
        List<String> offlineStatus = Arrays.asList(RobotStatusEnum.OFFLINE.getValue(), RobotStatusEnum.ERROR.getValue());
        queryWrapper.notIn("status", offlineStatus);
        return this.count(queryWrapper);
    }

    @Override
    public long countChargingRobots() {
        QueryWrapper<ChargingRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", RobotStatusEnum.CHARGING.getValue());
        return this.count(queryWrapper);
    }

    @Override
    public long countIdleRobots() {
        QueryWrapper<ChargingRobot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", RobotStatusEnum.IDLE.getValue());
        return this.count(queryWrapper);
    }
} 