package com.ruoyi.fire.service.impl;

import com.github.pagehelper.PageHelper;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.fire.domain.FireFacility;
import com.ruoyi.fire.mapper.FireFacilityMapper;
import com.ruoyi.fire.service.IFireFacilityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;

/**
 * 消防设施服务实现类
 * 实现接口定义的所有业务逻辑，包含状态动态计算、CRUD操作等
 *
 * @author Junhua
 * @date 2025-07-15
 */
@Service
public class FireFacilityServiceImpl implements IFireFacilityService {
    // 消防设施状态常量定义
    private static final Integer STATUS_NORMAL = 0;     // 正常
    private static final Integer STATUS_WILL_EXPIRE = 1; // 即将过期
    private static final Integer STATUS_EXPIRED = 2;      // 已过期
    private static final Integer STATUS_REPAIRING = 3;    // 维修中
    private static final Integer STATUS_REPLACED = 4;     // 已更换
    private static final Integer STATUS_SCRAPPED = 5;     // 已报废

    // 日志记录器
    private static final Logger log = LoggerFactory.getLogger(FireFacilityServiceImpl.class);

    // 注入数据访问层（Mapper）
    @Autowired
    private FireFacilityMapper fireFacilityMapper;

    /**
     * 检查并更新设施状态（核心逻辑）
     */
    @Override
    @Transactional(rollbackFor = Exception.class) // 事务管理：异常时回滚
    public int checkAndUpdateStatus(Long id) {
        // 1. 参数校验
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("设施ID无效（必须为正整数）");
        }

        // 2. 查询设施信息
        FireFacility facility = fireFacilityMapper.selectFireFacilityById(id);
        if (facility == null) {
            throw new RuntimeException("未查询到ID为" + id + "的消防设施");
        }

        // 3. 计算应有的动态状态
        Integer dynamicStatus = calculateDynamicStatus(facility.getExpiryDate(), facility.getStatus());
        Integer currentStatus = facility.getStatus();

        // 4. 特殊状态（维修中/已更换/已报废）不更新
        if (currentStatus != null && (
                currentStatus == STATUS_REPAIRING ||
                        currentStatus == STATUS_REPLACED ||
                        currentStatus == STATUS_SCRAPPED)) {
            log.info("设施[ID:{}]处于特殊状态({})，不执行状态更新", id, currentStatus);
            return 0;
        }

        // 5. 状态变化时执行更新
        if (!dynamicStatus.equals(currentStatus)) {
            facility.setStatus(dynamicStatus);
            facility.setUpdateTime(new Date()); // 更新时间戳
            int updateRows = fireFacilityMapper.updateFireFacility(facility);
            log.info("设施[ID:{}]状态更新：{} → {}", id, currentStatus, dynamicStatus);
            return updateRows > 0 ? 1 : 0;
        }

        // 6. 状态未变化
        log.info("设施[ID:{}]状态未发生变化（当前状态：{}）", id, currentStatus);
        return 0;
    }

    /**
     * 计算动态状态（核心算法）
     * 根据过期日期和当前状态，自动判断应有的状态
     */
    private Integer calculateDynamicStatus(Date expiryDate, Integer originalStatus) {
        // 处理原始状态为null的情况（默认正常）
        if (originalStatus == null) {
            originalStatus = STATUS_NORMAL;
        }

        // 特殊状态直接返回（不参与动态计算）
        if (originalStatus == STATUS_REPAIRING ||
                originalStatus == STATUS_REPLACED ||
                originalStatus == STATUS_SCRAPPED) {
            return originalStatus;
        }

        // 无过期日期时默认正常
        if (expiryDate == null) {
            return STATUS_NORMAL;
        }

        try {
            // 转换日期为LocalDate（处理时区问题）
            LocalDate today = LocalDate.now();
            LocalDate expiryLocalDate = expiryDate.toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();

            // 计算与过期日期的天数差
            long daysDiff = ChronoUnit.DAYS.between(today, expiryLocalDate);

            // 判断状态
            if (daysDiff < 0) {
                return STATUS_EXPIRED; // 已过期（过期日期在今天之前）
            } else if (daysDiff <= 30) {
                return STATUS_WILL_EXPIRE; // 即将过期（30天内过期）
            } else {
                return STATUS_NORMAL; // 正常（30天以上过期）
            }
        } catch (Exception e) {
            log.error("日期转换失败，expiryDate={}", expiryDate, e);
            throw new RuntimeException("处理过期日期时发生错误，请检查日期格式是否合法");
        }
    }

    /**
     * 分页更新设施状态（用于列表查询时批量刷新）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkAndUpdateExpirationStatus(FireFacility fireFacility, Integer pageNum, Integer pageSize) {
        // 1. 分页查询当前页数据
        PageHelper.startPage(pageNum, pageSize);
        List<FireFacility> facilityList = fireFacilityMapper.selectFireFacilityList(fireFacility);
        log.info("开始更新第{}页设施状态，共{}条数据", pageNum, facilityList.size());

        // 2. 遍历当前页数据，逐个更新状态
        Date now = new Date();
        for (FireFacility facility : facilityList) {
            // 跳过特殊状态的设施
            if (facility.getStatus() != null && (
                    facility.getStatus() == STATUS_REPAIRING ||
                            facility.getStatus() == STATUS_REPLACED ||
                            facility.getStatus() == STATUS_SCRAPPED)) {
                continue;
            }

            // 计算新状态并更新
            Integer newStatus = calculateDynamicStatus(facility.getExpiryDate(), facility.getStatus());
            if (!newStatus.equals(facility.getStatus())) {
                facility.setStatus(newStatus);
                facility.setUpdateTime(now);
                fireFacilityMapper.updateFireFacility(facility);
                log.debug("批量更新 - 设施[ID:{}]状态：{} → {}", facility.getId(), facility.getStatus(), newStatus);
            }
        }
    }

    /**
     * 根据ID查询设施
     */
    @Override
    public FireFacility selectFireFacilityById(Long id) {
        return fireFacilityMapper.selectFireFacilityById(id);
    }

    /**
     * 查询设施列表
     */
    @Override
    public List<FireFacility> selectFireFacilityList(FireFacility fireFacility) {
        return fireFacilityMapper.selectFireFacilityList(fireFacility);
    }

    /**
     * 新增设施
     */
    @Override
    public int insertFireFacility(FireFacility fireFacility) {
        // 设置创建/更新时间
        Date now = new Date();
        fireFacility.setCreateTime(now);
        fireFacility.setUpdateTime(now);
        // 自动计算初始状态
        fireFacility.setStatus(calculateDynamicStatus(fireFacility.getExpiryDate(), null));
        return fireFacilityMapper.insertFireFacility(fireFacility);
    }

    /**
     * 修改设施
     */
    @Override
    public int updateFireFacility(FireFacility fireFacility) {
        // 更新时间戳
        fireFacility.setUpdateTime(new Date());
        return fireFacilityMapper.updateFireFacility(fireFacility);
    }

    /**
     * 批量删除设施
     */
    @Override
    public int deleteFireFacilityByIds(Long[] ids) {
        return fireFacilityMapper.deleteFireFacilityByIds(ids);
    }

    /**
     * 单个删除设施
     */
    @Override
    public int deleteFireFacilityById(Long id) {
        return fireFacilityMapper.deleteFireFacilityById(id);
    }

    /**
     * 导入设施数据
     */
    @Override
    public String importFireFacility(MultipartFile file, boolean updateSupport) throws Exception {
        ExcelUtil<FireFacility> util = new ExcelUtil<>(FireFacility.class);
        List<FireFacility> facilityList = util.importExcel(file.getInputStream());

        // 校验导入数据
        if (StringUtils.isEmpty(facilityList)) {
            throw new Exception("导入数据为空，请检查Excel文件内容");
        }

        int successNum = 0; // 成功数量
        int failureNum = 0; // 失败数量
        StringBuilder failureMsg = new StringBuilder(); // 失败原因
        Date now = new Date();

        // 遍历处理每条数据
        for (FireFacility facility : facilityList) {
            try {
                // 基础校验：名称和位置ID不能为空
                if (StringUtils.isEmpty(facility.getFacilityName()) || StringUtils.isEmpty(facility.getLocationId())) {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、设施名称或位置ID为空");
                    continue;
                }

                // 检查是否已存在（根据位置+名称判断）
                FireFacility existFacility = selectByLocationAndName(facility.getLocationId(), facility.getFacilityName());
                if (existFacility == null) {
                    // 新增
                    facility.setCreateTime(now);
                    facility.setUpdateTime(now);
                    facility.setStatus(calculateDynamicStatus(facility.getExpiryDate(), null));
                    fireFacilityMapper.insertFireFacility(facility);
                    successNum++;
                } else if (updateSupport) {
                    // 更新已存在的数据
                    facility.setId(existFacility.getId()); // 覆盖ID
                    facility.setCreateTime(existFacility.getCreateTime()); // 保留创建时间
                    facility.setUpdateTime(now); // 更新时间戳
                    fireFacilityMapper.updateFireFacility(facility);
                    successNum++;
                } else {
                    // 不允许更新，视为失败
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、设施[" + facility.getFacilityName() + "]已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String facilityName = (facility.getFacilityName() != null) ? facility.getFacilityName() : "未知设施";
                failureMsg.append("<br/>" + failureNum + "、设施[" + facilityName + "]导入失败：" + e.getMessage());
                log.error("导入设施失败", e);
            }
        }

        // 组装结果
        if (failureNum > 0) {
            failureMsg.insert(0, "导入失败，共" + failureNum + "条数据异常：");
            throw new Exception(failureMsg.toString());
        } else {
            return "导入成功，共处理" + successNum + "条数据";
        }
    }

    /**
     * 查询设施详情列表
     */
    @Override
    public List<FireFacility> getDetails(FireFacility fireFacility) {
        return fireFacilityMapper.getDetails(fireFacility);
    }

    /**
     * 根据位置和名称查询设施（用于导入时判断重复）
     */
    @Override
    public FireFacility selectByLocationAndName(String locationId, String facilityName) {
        return fireFacilityMapper.selectByLocationAndName(locationId, facilityName);
    }
}