package com.yfd.platform.modules.experimentalData.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.modules.experimentalData.domain.TsTask;
import com.yfd.platform.modules.experimentalData.mapper.TsTaskMapper;
import com.yfd.platform.modules.experimentalData.service.ITsFilesService;
import com.yfd.platform.modules.experimentalData.service.ITsNodesService;
import com.yfd.platform.modules.experimentalData.service.ITsTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.specialDocument.domain.Project;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.BatchDeleteRequest;
import com.yfd.platform.modules.storage.model.request.NewFolderRequest;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.utils.StringUtils;
import io.netty.channel.ChannelInboundHandlerAdapter;
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 javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 试验任务表 服务实现类
 * </p>
 *
 * @author LiMengNan
 * @since 2025-01-21
 */
@Service
public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> implements ITsTaskService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ChannelInboundHandlerAdapter.class);


    //试验任务Mapper
    @Resource
    private TsTaskMapper tsTaskMapper;

    //实验数据管理
    @Resource
    private ITsNodesService tsNodesService;

    @Resource
    private StorageSourceContext storageSourceContext;


    private static final String INITIAL_CODE = "00001";
    private static final int MAX_CODE_VALUE = 99999;

    /**********************************
     * 用途说明: 分页查询试验数据管理-试验任务管理
     * 参数说明
     * taskName      任务名称
     * startDate     (开始日期)
     * endDate      （结束日期）
     * taskPlace     任务地点
     * taskPerson    任务人员
     * taskCode      任务编号
     * taskType      任务类型
     * carrierName    载体名称
     * deviceCode    设备代号_编号
     * testDescribe    试验描述
     * sensorDescribe    传感器描述
     * pageNum 当前页
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
     ***********************************/
    @Override
    public Page<TsTask> getTsTaskPage(String taskName, String startDate, String endDate, String taskPlace, String taskPerson, String taskCode, String taskType, String carrierName, String deviceCode, String testDescribe, String sensorDescribe, Page<TsTask> page) {

        LambdaQueryWrapper<TsTask> queryWrapper = new LambdaQueryWrapper<>();
        //如果任务名称    taskName 不为空
        if (StringUtils.isNotEmpty(taskName)) {
            queryWrapper.like(TsTask::getTaskName, taskName);
        }

        //如果任务地点   taskPlace 不为空
        if (StringUtils.isNotEmpty(taskPlace)) {
            queryWrapper.like(TsTask::getTaskPlace, taskPlace);
        }

        //如果任务人员  taskPerson 不为空
        if (StringUtils.isNotEmpty(taskPerson)) {
            queryWrapper.like(TsTask::getTaskPerson, taskPerson);
        }

        //如果任务编号  taskCode 不为空
        if (StringUtils.isNotEmpty(taskCode)) {
            queryWrapper.like(TsTask::getTaskCode, taskCode);
        }

        //如果任务类型  taskType 不为空
        if (StringUtils.isNotEmpty(taskType)) {
            queryWrapper.eq(TsTask::getTaskType, taskType);
        }
        //如果载体名称  carrierName 不为空
        if (StringUtils.isNotEmpty(carrierName)) {
            queryWrapper.like(TsTask::getCarrierName, carrierName);
        }
        //如果设备代号_编号  deviceCode 不为空
        if (StringUtils.isNotEmpty(deviceCode)) {
            queryWrapper.like(TsTask::getDeviceCode, deviceCode);
        }
        //如果试验描述  testDescribe 不为空
        if (StringUtils.isNotEmpty(testDescribe)) {
            queryWrapper.like(TsTask::getTestDescribe, testDescribe);
        }
        //如果传感器描述  sensorDescribe 不为空
        if (StringUtils.isNotEmpty(sensorDescribe)) {
            queryWrapper.like(TsTask::getSensorDescribe, sensorDescribe);
        }


        //开始时间startDate
        DateTime parseStartDate = DateUtil.parse(startDate);
        //时间endDate不为空
        DateTime parseEndDate = DateUtil.parse(endDate);
        //开始时间和结束时间不为空    查询条件>=开始时间  <结束时间
        if (parseStartDate != null && parseEndDate != null) {
            queryWrapper.ge(TsTask::getTaskStartdate, parseStartDate).lt(TsTask::getTaskEnddate, parseEndDate);
        }
        queryWrapper.orderByDesc(TsTask::getTaskStartdate);
        //分页查询
        Page<TsTask> tsTaskPage = tsTaskMapper.selectPage(page, queryWrapper);
        return tsTaskPage;
    }

    /***********************************
     * 用途说明：新增试验数据管理-试验任务管理
     * 参数说明
     * TsTask     试验任务管理
     * 返回值说明:  com.yfd.platform.config.ResponseResult 返回新增成功或者失败
     ***********************************/
    @Override
    public Boolean addSdproject(TsTask tsTask) {
        //todo  新增实验任务的时候创建一个本地的文件夹
        //生成任务编号
        String taskCode = generateNextTsTaskCode();
        tsTask.setTaskCode(taskCode);

        //生成任务名称   任务开始时间_结束时间_地点_载机名称_设备代号_编号
        String taskName = buildTaskName(tsTask);
        tsTask.setTaskName(taskName);

        // 设置当前时间
        LocalDateTime now = LocalDateTime.now();
        // 转换为 Timestamp
        Timestamp currentTime = Timestamp.valueOf(now);
        tsTask.setCreateTime(currentTime);
        int valueAdded = tsTaskMapper.insert(tsTask);
        if (valueAdded == 1) {

            // 根节点路径
            String path = "/";
            //新增节点的时候 创建文件夹
            NewFolderRequest newFolderRequest = new NewFolderRequest();
            newFolderRequest.setName(tsTask.getTaskName());//新建的文件夹名称,示例值(/a/b/c)
            newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问，则支持请求密码,示例值(123456)
            newFolderRequest.setPath(path);//请求路径,示例值(/)
            newFolderRequest.setStorageKey("local");//存储源 key,示例值(local minio)
            AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
            boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
            if (flag) {
                return true;
            } else {
                LOGGER.error("试验任务增加成功，但是本地试验任务文件夹创建失败");
                return false;
            }
        } else {
            return false;
        }
    }


    public static String buildTaskName(TsTask tsTask) {
        List<String> parts = new ArrayList<>();

        // 按顺序添加非空字段
        addIfNotEmpty(parts, String.valueOf(tsTask.getTaskStartdate()));
        addIfNotEmpty(parts, String.valueOf(tsTask.getTaskEnddate()));
        addIfNotEmpty(parts, tsTask.getTaskPlace());
        addIfNotEmpty(parts, tsTask.getCarrierName());
        addIfNotEmpty(parts, tsTask.getDeviceCode());

        // 使用下划线连接非空部分
        return String.join("_", parts);
    }

    private static void addIfNotEmpty(List<String> list, String value) {
        if (StringUtils.isNotBlank(value)) { // 使用Apache Commons Lang的空判断
            list.add(value.trim()); // 去除首尾空格
        }
    }

    // 备用方案（不使用第三方库）
    private static boolean isNotEmpty(String value) {
        return value != null && !value.trim().isEmpty();
    }

    /**********************************
     * 用途说明: 修改试验数据管理-试验任务管理
     * 参数说明
     * TsTask     试验任务管理
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败
     ***********************************/
    @Override
    public boolean updatetsTask(TsTask tsTask) {

        //生成任务名称   任务开始时间_结束时间_地点_载机名称_设备代号_编号
        String taskName = buildTaskName(tsTask);
        tsTask.setTaskName(taskName);
        int valueUpdate = tsTaskMapper.updateById(tsTask);
        if (valueUpdate == 1) {
            return true;
        } else {
            return false;
        }
    }

    /**********************************
     * 用途说明: 批量删除试验数据管理-试验任务管理
     * 参数说明  ids 试验数据管理id数组
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回批量删除成功或失败
     ***********************************/
    @Override
    public boolean deleteTstaskByIds(List<String> dataset) {
        Boolean value = false;

        //循环所有的ID
        for (String taskId : dataset) {

            TsTask tsTask = tsTaskMapper.selectById(taskId);
            String path = "/" + tsTask.getTaskName() + "/";
            //调用删除节点 根据任务ID
            Boolean deleteTsnodes = tsNodesService.deleteTsNodesByTaskId(taskId, path);
            //如果删除成功 接着删除节点表数据
            if (deleteTsnodes) {
                LOGGER.info("tsNodes表结删除改成功");
                value = true;
            } else {
                LOGGER.error("tsNodes表结构删除失败");
                value = false;
            }


            // 删除 local 中的文件夹  项目文件夹
            List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
            BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem();
            deleteItemData.setName(tsTask.getTaskName());
            deleteItemData.setPassword("");
            deleteItemData.setPath("/");
            deleteItemData.setType(FileTypeEnum.FOLDER);
            deleteItemList.add(deleteItemData);

            BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest();
            batchDeleteRequest.setDeleteItems(deleteItemList);
            batchDeleteRequest.setStorageKey("local");
            AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
            int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList);

            for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) {
                boolean flag = false;
                try {
                    if (deleteItem.getType() == FileTypeEnum.FILE) {
                        flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName());
                    } else if (deleteItem.getType() == FileTypeEnum.FOLDER) {
                        flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName());
                    }

                    if (flag) {
                        deleteSuccessCount++;
                    } else {
                        deleteFailCount++;
                    }
                } catch (Exception e) {
                    LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e);
                    deleteFailCount++;
                }
            }

            if (deleteSuccessCount >= 1) {
                // 删除当前项目
                int deleteCount = tsTaskMapper.deleteById(taskId);
                if (deleteCount == 1) {
                    LOGGER.info("tstask表结删除改成功");
                    value = true;
                } else {
                    LOGGER.error("tstask表结构删除失败");
                    value = false;
                }
            } else {
                value = false;
            }


        }

        return value;
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateNextTsTaskCode() {
        // 1. 使用悲观锁查询最大编号
        TsTask maxTsTask = this.getOne(
                new QueryWrapper<TsTask>()
                        .select("MAX(task_code) AS taskCode")
                        .last("FOR UPDATE")
        );


        // 2. 处理空表情况
        String currentMax = (maxTsTask != null && maxTsTask.getTaskCode() != null)
                ? maxTsTask.getTaskCode()
                : INITIAL_CODE;

        // 3. 验证并生成新编号
        try {
            int numericCode = Integer.parseInt(currentMax);
            if (numericCode < 0 || numericCode > MAX_CODE_VALUE) {
                throw new IllegalStateException("当前设备编号超出有效范围: " + currentMax);
            }
            if (numericCode == MAX_CODE_VALUE) {
                throw new IllegalStateException("设备编号已达最大值" + MAX_CODE_VALUE);
            }
            return String.format("%05d", numericCode + 1);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("无效的设备编号格式: " + currentMax);
        }

    }
}
