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.ParkingSpotMapper;
import com.yupi.project.model.entity.ParkingSpot;
import com.yupi.project.model.enums.ParkingSpotStatusEnum;
import com.yupi.project.service.ParkingSpotService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
* @author Yupi
* @description 针对表【parking_spot(车位表)】的数据库操作Service实现
* @createDate 2023-12-03 10:00:00
*/
@Service
@Slf4j
public class ParkingSpotServiceImpl extends ServiceImpl<ParkingSpotMapper, ParkingSpot>
    implements ParkingSpotService {

    @Override
    @Transactional
    public ParkingSpot addParkingSpot(String spotUid, String locationDescription, boolean robotAssignable) {
        if (findBySpotUid(spotUid) != null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "车位UID已存在: " + spotUid);
        }
        ParkingSpot spot = new ParkingSpot();
        spot.setSpotUid(spotUid);
        spot.setLocationDescription(locationDescription);
        spot.setRobotAssignable(robotAssignable);
        spot.setStatus(ParkingSpotStatusEnum.AVAILABLE.getValue()); // 默认可用
        spot.setCreateTime(new Date());
        spot.setUpdateTime(new Date());
        boolean saved = this.save(spot);
        if (!saved) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "添加车位失败");
        }
        log.info("车位添加成功: {}", spot);
        return spot;
    }

    @Override
    public ParkingSpot findBySpotUid(String spotUid) {
        QueryWrapper<ParkingSpot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("spot_uid", spotUid);
        return this.getOne(queryWrapper);
    }

    @Override
    @Transactional
    public boolean updateParkingSpotStatus(Long spotId, ParkingSpotStatusEnum newStatus, Long currentSessionId) {
        ParkingSpot spot = this.getById(spotId);
        if (spot == null) {
            log.warn("旧版 updateParkingSpotStatus: 车位不存在, spotId: {}", spotId);
            // throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "车位不存在");
            // 为了与新方法的行为保持一致（新方法如果UID找不到会返回false），这里也返回false
            return false; 
        }
        // 调用新的基于UID的方法
        return this.updateSpotStatus(spot.getSpotUid(), newStatus, currentSessionId);
    }

    @Override
    public List<ParkingSpot> findAvailableAndAssignableSpots() {
        QueryWrapper<ParkingSpot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", ParkingSpotStatusEnum.AVAILABLE.getValue());
        queryWrapper.eq("robot_assignable", true);
        return this.list(queryWrapper);
    }

    @Override
    @Transactional
    public boolean occupySpot(Long spotId, Long sessionId, ParkingSpotStatusEnum targetStatus) {
        ParkingSpot spot = this.getById(spotId);
        if (spot == null) {
            log.warn("OccupySpot: 车位不存在, spotId: {}", spotId);
            // throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "车位不存在");
            return false; // 与新 updateSpotStatus 行为一致
        }
        // 校验车位是否可被占用 (例如必须是AVAILABLE状态)
        if (!ParkingSpotStatusEnum.AVAILABLE.getValue().equals(spot.getStatus())) {
            log.warn("尝试占用一个非可用车位: spotId={}, currentStatus={}", spotId, spot.getStatus());
            // throw new BusinessException(ErrorCode.OPERATION_ERROR, "车位当前状态不可占用");
            return false; // 状态不符，占用失败
        }
        if (!spot.getRobotAssignable()) {
             log.warn("尝试占用一个不可指派机器人的车位: spotId={}", spotId);
            //  throw new BusinessException(ErrorCode.OPERATION_ERROR, "车位不可指派机器人");
             return false; // 不可指派，占用失败
        }

        // return updateParkingSpotStatus(spotId, targetStatus, sessionId); // 旧调用
        return this.updateSpotStatus(spot.getSpotUid(), targetStatus, sessionId); // 新调用
    }

    @Override
    @Transactional
    public boolean releaseSpot(Long spotId) {
        ParkingSpot spot = this.getById(spotId);
        if (spot == null) {
            log.warn("尝试释放车位失败，车位不存在: {}", spotId);
            return false; 
        }
        // 只有非AVAILABLE的车位才需要被释放回AVAILABLE
        // 新的 updateSpotStatus 内部会检查是否真的需要更新，所以这里的检查可以简化或移除
        // if (ParkingSpotStatusEnum.AVAILABLE.getValue().equals(spot.getStatus())) {
        //     log.info("车位 {} (UID: {}) 本身已是可用状态，无需释放。", spotId, spot.getSpotUid());
        //     return true; 
        // }
        // return updateParkingSpotStatus(spotId, ParkingSpotStatusEnum.AVAILABLE, null); // 旧调用
        return this.updateSpotStatus(spot.getSpotUid(), ParkingSpotStatusEnum.AVAILABLE, null); // 新调用
    }

    @Override
    @Transactional
    public boolean updateSpotStatus(String spotUID, ParkingSpotStatusEnum newStatus, Long currentSessionId) {
        if (StringUtils.isBlank(spotUID) || newStatus == null) {
            log.warn("更新车位状态失败：spotUID 或 newStatus 为空。spotUID: {}, newStatus: {}", spotUID, newStatus);
            return false;
        }

        ParkingSpot parkingSpot = this.findBySpotUid(spotUID);
        if (parkingSpot == null) {
            log.warn("更新车位状态失败：未找到 UID 为 {} 的车位。", spotUID);
            return false;
        }

        // 彻底重构：创建一个包含所有最终状态的更新对象，避免复杂的条件逻辑。
        // 这是解决顽固的 "empty set clause" 问题的最稳健方法。
        
        boolean needsUpdate = false;
        
        // 检查状态是否需要更新
        if (!newStatus.getValue().equals(parkingSpot.getStatus())) {
            needsUpdate = true;
        }
        
        // 检查会话ID是否需要更新
        Long targetSessionId = (newStatus == ParkingSpotStatusEnum.AVAILABLE) ? null : currentSessionId;
        if (targetSessionId == null && parkingSpot.getCurrentSessionId() != null) {
            needsUpdate = true;
        } else if (targetSessionId != null && !targetSessionId.equals(parkingSpot.getCurrentSessionId())) {
            needsUpdate = true;
        }

        if (!needsUpdate) {
            log.info("车位 {} 的状态与数据库一致 (状态: {}, 会话ID: {})，无需更新。",
                    spotUID, newStatus, currentSessionId == null ? "null" : currentSessionId);
            return true; // 数据一致，操作成功
        }

        // 创建一个完整的更新实体
        ParkingSpot spotToUpdate = new ParkingSpot();
        spotToUpdate.setId(parkingSpot.getId());
        spotToUpdate.setStatus(newStatus.getValue());
        
        if (newStatus == ParkingSpotStatusEnum.AVAILABLE) {
            spotToUpdate.setCurrentSessionId(null);
        } else {
            spotToUpdate.setCurrentSessionId(currentSessionId);
        }

        boolean success = this.updateById(spotToUpdate);
        if (success) {
            log.info("成功更新车位 {} 的状态。新状态: {}, 当前会话ID: {}",
                    spotUID, spotToUpdate.getStatus(), spotToUpdate.getCurrentSessionId() == null ? "null" : spotToUpdate.getCurrentSessionId());
        } else {
            log.error("更新车位 {} 的状态失败 (数据库操作失败)。", spotUID);
        }
        return success;
    }

    @Override
    public long countAvailableSpots() {
        QueryWrapper<ParkingSpot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", ParkingSpotStatusEnum.AVAILABLE.getValue());
        return this.count(queryWrapper);
    }
} 