package com.wms_main.service.business.serviceImpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.constant.enums.wms.WmsAgvLockEnums;
import com.wms_main.dao.ITAppAgvLockService;
import com.wms_main.dao.ITAppTaskService;
import com.wms_main.model.po.TAppAgvLock;
import com.wms_main.model.po.TAppTask;
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.business.IAgvLockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 入库口互锁服务实现
 * 管理单一入库口的AGV上料互锁机制
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AgvLockServiceImpl implements IAgvLockService {

    private final ITAppAgvLockService agvLockService;
    private final ITAppTaskService appTaskService;
    
    private static final String DEFAULT_INBOUND_PORT = "R1"; // 默认入库口
    private static final int DEFAULT_TIMEOUT_SECONDS = 600; // 默认超时时间10分钟

    @Override
    @Transactional
    public TAppAgvLock lockInboundPort(String agvId, String inboundPort) {
        if (StringUtils.isEmpty(agvId)) {
            log.warn("AGV ID为空");
            return null;
        }
        
        // 使用默认入库口如果未指定
        if (StringUtils.isEmpty(inboundPort)) {
            inboundPort = DEFAULT_INBOUND_PORT;
        }

        // 清理超时锁定
        cleanTimeoutLocks();

        // 检查入库口是否已被占用
        List<TAppAgvLock> existingLocks = agvLockService.list(new LambdaQueryWrapper<TAppAgvLock>().eq(TAppAgvLock::getFeedStation, inboundPort));
        if (existingLocks == null || existingLocks.isEmpty()) {
            return createInboundPortLock(agvId, inboundPort);
        } else {
            agvLockService.update(
                    new LambdaUpdateWrapper<TAppAgvLock>()
                            .eq(TAppAgvLock::getFeedStation, inboundPort)
                            .eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
                            .set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
                            .set(TAppAgvLock::getLockTime, LocalDateTime.now())
                            .set(TAppAgvLock::getRemark, "AGV就位并放货，锁定入库口")
            );
            return null;
        }
    }

    @Override
    public boolean canFeedToInboundPort(String inboundPort) {
        // 使用默认入库口如果未指定
        if (StringUtils.isEmpty(inboundPort)) {
            inboundPort = DEFAULT_INBOUND_PORT;
        }
        
        // 清理超时锁定
        cleanTimeoutLocks();
        
        // 检查入库口是否有活动的锁定
        List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
        boolean hasActiveLock = activeLocks.stream()
                .anyMatch(lock -> lock.getLockStatus() == 1);
        
        if (hasActiveLock) {
            log.debug("入库口 {} 当前被占用，无法上料", inboundPort);
            return false;
        }
        
        // 检查是否有正在处理的入库任务
        int processingTasks = getProcessingTaskCount(inboundPort);
        boolean canFeed = processingTasks == 0;
        
        log.debug("入库口 {} 可上料状态: {}, 处理中任务数: {}", inboundPort, canFeed, processingTasks);
        return canFeed;
    }

    @Override
    public int getProcessingTaskCount(String inboundPort) {
        // 使用默认入库口如果未指定
        if (StringUtils.isEmpty(inboundPort)) {
            inboundPort = DEFAULT_INBOUND_PORT;
        }
        
        // 统计正在处理的入库任务数量（包括等待、运行状态的任务）
        List<TAppTask> processingTasks = appTaskService.list(
                new LambdaQueryWrapper<TAppTask>()
                        .eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode())
                        .in(TAppTask::getTaskStatus, 
                            WmsStackerTaskStatusEnums.WAIT.getCode(),
                            WmsStackerTaskStatusEnums.RUN.getCode())
                        .like(TAppTask::getOrigin, inboundPort)  // 假设任务来源包含入库口信息
        );
        
        return processingTasks.size();
    }

    @Override
    public String getInboundPortStatus(String inboundPort) {
        // 使用默认入库口如果未指定
        if (StringUtils.isEmpty(inboundPort)) {
            inboundPort = DEFAULT_INBOUND_PORT;
        }
        
        // 检查是否有活动锁定
        List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
        boolean hasActiveLock = activeLocks.stream()
                .anyMatch(lock -> lock.getLockStatus() == 1);
                
        if (hasActiveLock) {
            return "占用";
        }
        
        // 检查是否有处理中的任务
        int processingTasks = getProcessingTaskCount(inboundPort);
        if (processingTasks > 0) {
            return "占用";
        }
        
        return "空闲";
    }

    @Override
    @Transactional
    public int cleanTimeoutLocks() {
        List<TAppAgvLock> timeoutLocks = agvLockService.getTimeoutLocks();
        if (timeoutLocks.isEmpty()) {
            return 0;
        }

        try {
            for (TAppAgvLock lock : timeoutLocks) {
                agvLockService.update(
                        new LambdaUpdateWrapper<TAppAgvLock>()
                                .eq(TAppAgvLock::getLockId, lock.getLockId())
                                .set(TAppAgvLock::getLockStatus, 0)
                                .set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
                                .set(TAppAgvLock::getRemark, "超时自动释放")
                );
                
                log.info("释放超时锁定: AGV {} 在入库口 {}", lock.getAgvId(), lock.getFeedStation());
            }
            
            log.info("清理了 {} 个超时锁定", timeoutLocks.size());
            return timeoutLocks.size();
        } catch (Exception e) {
            log.error("清理超时锁定失败", e);
            return 0;
        }
    }

    @Override
    @Transactional
    public int releaseAllInboundPortLocks(String inboundPort) {
        // 使用默认入库口如果未指定
        if (StringUtils.isEmpty(inboundPort)) {
            inboundPort = DEFAULT_INBOUND_PORT;
        }
        
        try {
            // 释放指定入库口的所有活动锁定
            agvLockService.update(
                    new LambdaUpdateWrapper<TAppAgvLock>()
                            .eq(TAppAgvLock::getFeedStation, inboundPort)
                            .eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
                            .set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
                            .set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
                            .set(TAppAgvLock::getRemark, "入库任务完成，批量释放锁定")
            );
            
            // 查询实际释放的锁定数量
            List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
            int releasedCount = (int) activeLocks.stream()
                    .filter(lock -> lock.getLockStatus() == 0)
                    .count();
            
            log.info("释放入库口 {} 的所有锁定，共释放 {} 个锁定", inboundPort, releasedCount);
            return releasedCount;
        } catch (Exception e) {
            log.error("释放入库口 {} 的所有锁定失败", inboundPort, e);
            return 0;
        }
    }

    /**
     * 创建入库口锁定记录
     */
    private TAppAgvLock createInboundPortLock(String agvId, String inboundPort) {
        TAppAgvLock lock = new TAppAgvLock();
        lock.setLockId(UUIDUtils.getNewUUID());
        lock.setAgvId(agvId);
        lock.setFeedStation(inboundPort);
        lock.setLockStatus(1);
        lock.setLockType("INBOUND_PORT_LOCK");
        lock.setPriority(1);
        lock.setQueuePosition(1);
        lock.setLockTime(LocalDateTime.now());
        lock.setTimeoutSeconds(DEFAULT_TIMEOUT_SECONDS);
        lock.setCreateTime(LocalDateTime.now());
        lock.setUpdateTime(LocalDateTime.now());
        lock.setRemark("AGV就位并放货，锁定入库口");

        if (agvLockService.save(lock)) {
            log.info("AGV {} 成功锁定入库口 {}", agvId, inboundPort);
            return lock;
        }
        
        log.error("AGV {} 锁定入库口 {} 失败", agvId, inboundPort);
        return null;
    }
}