package org.springblade.file.listener;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.utils.Func;
import org.springblade.file.callback.UnzipCallback;
import org.springblade.file.callback.UnzipEventType;
import org.springblade.file.pojo.entity.BusinessUnzipTask;
import org.springblade.file.pojo.enums.UnzipTask;
import org.springblade.file.pojo.vo.FileVO;
import org.springblade.file.service.IBusinessUnzipDetailService;
import org.springblade.file.service.IBusinessUnzipTaskService;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *  文件监听器
 * @author bfhuange
 * @date 2024/11/8
 */
@Slf4j
@Component
public class FileListener {

    private final IBusinessUnzipTaskService taskService;
    private final IBusinessUnzipDetailService detailService;
    private final Map<String, UnzipCallback> callbackMap;

    public FileListener(IBusinessUnzipTaskService taskService, IBusinessUnzipDetailService detailService, List<UnzipCallback> callbacks) {
        this.taskService = taskService;
        this.detailService = detailService;
        this.callbackMap = callbacks.stream()
                .collect(Collectors.toMap(UnzipCallback::getBizCode, Function.identity(), (a, b) -> {
                    throw new ServiceException("重复的解压完成回调接口");
                }));
    }

    /**
     *  文件上传完成监听器
     * @param event
     */
    @Async
    @TransactionalEventListener(value = FileUploadedEvent.class, phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
    public void fileUploaded(FileUploadedEvent event) {
        try {
            Long fileTaskId = event.getFileTaskId();
            log.info("文件上传任务完成事件 id：{}", fileTaskId);
            BusinessUnzipTask businessUnzipTask = taskService.getOne(Wrappers.<BusinessUnzipTask>lambdaQuery()
                    .eq(BusinessUnzipTask::getRelateId, fileTaskId)
                    .last("limit 1")
            );
            if (businessUnzipTask != null) {
                // 存在解压任务，更新任务为上传完成
                BusinessUnzipTask updateParam = new BusinessUnzipTask();
                updateParam.setId(businessUnzipTask.getId());
                updateParam.setStatus(UnzipTask.Status.UPLOADED.getCode());
                taskService.updateById(updateParam);
                // 解压开始
                this.unzipStart(new UnzipStartEvent(businessUnzipTask));
            }
        } catch (Exception e) {
            log.error("文件上传任务完成事件 异常", e);
        }
    }

    /**
     *  解压开始
     * @param event
     */
    @Async
    @TransactionalEventListener(value = UnzipStartEvent.class, phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
    public void unzipStart(UnzipStartEvent event) {
        try {
            Long unzipTaskId = event.getUnzipTaskId();
            BusinessUnzipTask task = event.getTask();
            log.info("解压开始事件 id：{} 业务解压任务：{}", unzipTaskId, JSON.toJSONString(task));
            if (task == null) {
                // 手动触发时，只有id
                task = taskService.getById(unzipTaskId);
            }
            // 回调接口
            callback(task, UnzipEventType.START);
            // 解压并保存
            detailService.unzipAndSaveAsync(task.getId(), taskService.getFile(task));
        } catch (Exception e) {
            log.error("解压开始事件 异常", e);
        }
    }

    /**
     *  解压完成监听器
     * @param event
     */
    @Async
    @EventListener(UnzipCompletedEvent.class)
    public void unzipCompleted(UnzipCompletedEvent event) {
        try {
            Long unzipTaskId = event.getUnzipTaskId();
            log.info("解压完成事件 id：{}", unzipTaskId);
            // 查询解压任务
            BusinessUnzipTask unzipTask = taskService.getById(unzipTaskId);
            Func.requireNotNull(unzipTask, "解压任务不存在");
            // 更新解压任务状态
            BusinessUnzipTask updateParam = new BusinessUnzipTask();
            updateParam.setId(unzipTaskId);
            updateParam.setStatus(UnzipTask.Status.FINISHED.getCode());
            taskService.updateById(updateParam);
            // 回调接口
            callback(unzipTask, UnzipEventType.SUCCESS);
        } catch (Exception e) {
            log.error("解压完成事件 异常", e);
        }
    }

    /**
     *  解压失败监听器
     * @param event
     */
    @Async
    @EventListener(UnzipFailEvent.class)
    public void unzipFail(UnzipFailEvent event) {
        try {
            Long unzipTaskId = event.getUnzipTaskId();
            log.info("解压失败事件 id：{}", unzipTaskId);
            // 查询解压任务
            BusinessUnzipTask unzipTask = taskService.getById(unzipTaskId);
            Func.requireNotNull(unzipTask, "解压任务不存在");
            // 更新解压任务状态
            BusinessUnzipTask updateParam = new BusinessUnzipTask();
            updateParam.setId(unzipTaskId);
            updateParam.setStatus(UnzipTask.Status.UNZIP_FAIL.getCode());
            taskService.updateById(updateParam);
            // 回调接口
            callback(unzipTask, UnzipEventType.FAIL);
        } catch (Exception e) {
            log.error("解压失败事件 异常", e);
        }
    }

    /**
     *  回调接口
     * @param unzipTask
     * @param event
     */
    private void callback(BusinessUnzipTask unzipTask, UnzipEventType event) {
        if (unzipTask == null) {
            log.warn("解压回调接口 解压任务为空");
            return;
        }
        UnzipCallback unzipCallback = callbackMap.get(unzipTask.getBizCode());
        if (unzipCallback == null) {
            log.error("未配置业务编码：{}对应的解压回调接口", unzipTask.getBizCode());
            return;
        }
        Boolean result = null;
        try {
            result = unzipCallback.callback(unzipTask.getBizId(), event.name());
        } catch (Exception e) {
            log.error("解压回调接口异常", e);
        }
        log.info("解压回调接口参数：{} 业务编码：{} 事件：{} 结果：{}", unzipTask.getBizId(), unzipTask.getBizCode(), event.name(), result);
    }
}
