package com.easyagents.document.core.async;

import com.easyagents.core.util.StringUtil;
import com.easyagents.document.core.exception.DocumentParseException;
import com.easyagents.document.core.entity.ParseResponse;
import com.easyagents.document.core.entity.ParseTaskInfo;
import com.easyagents.document.core.entity.ParseTaskStatus;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executor;

/**
 * 文档异步任务管理器。
 *
 * @author Codex
 * @since 2026-04-16
 */
public class DocumentAsyncTaskManager {

    private final DocumentAsyncTaskRepository repository;
    private final Executor executor;

    /**
     * 创建任务管理器。
     *
     * @param repository 任务仓库
     * @param executor 执行器
     */
    public DocumentAsyncTaskManager(DocumentAsyncTaskRepository repository, Executor executor) {
        if (repository == null) {
            throw new IllegalArgumentException("DocumentAsyncTaskRepository must not be null");
        }
        if (executor == null) {
            throw new IllegalArgumentException("Executor must not be null");
        }
        this.repository = repository;
        this.executor = executor;
    }

    /**
     * 提交异步任务。
     *
     * @param backend 后端标识
     * @param fileNames 文件名列表
     * @param runner 任务执行器
     * @return 初始任务状态
     */
    public ParseTaskStatus submit(String backend, List<String> fileNames, final DocumentAsyncTaskRunner runner) {
        final String taskId = UUID.randomUUID().toString();
        final ParseTaskStatus status = new ParseTaskStatus();
        status.setTaskId(taskId);
        status.setStatus("queued");
        status.setBackend(backend);
        status.setFileNames(fileNames == null ? new ArrayList<String>() : new ArrayList<String>(fileNames));
        status.setCreatedAt(Instant.now().toString());
        status.setCurrentStage("queued");
        status.setProgressPercent(0);
        status.setProcessedItems(0);
        status.setTotalItems(fileNames == null ? 0 : fileNames.size());
        status.setStatusMessage("任务已进入队列");

        final DocumentAsyncTaskRecord record = new DocumentAsyncTaskRecord(status);
        repository.save(record);

        executor.execute(new Runnable() {
            @Override
            public void run() {
                markRunning(record);
                try {
                    ParseResponse response = runner.run(new RepositoryBackedTaskUpdater(record));
                    ParseTaskStatus completed = record.getStatusSnapshot();
                    completed.setStatus("completed");
                    completed.setCompletedAt(Instant.now().toString());
                    completed.setProgressPercent(100);
                    completed.setCurrentStage("completed");
                    completed.setStatusMessage("任务执行完成");
                    record.setResult(response);
                    record.updateStatus(completed);
                } catch (Exception exception) {
                    ParseTaskStatus failed = record.getStatusSnapshot();
                    failed.setStatus("failed");
                    failed.setCompletedAt(Instant.now().toString());
                    failed.setCurrentStage("failed");
                    failed.setStatusMessage(exception.getMessage());
                    failed.setError(exception.getMessage());
                    record.updateStatus(failed);
                }
            }
        });

        return record.getStatusSnapshot();
    }

    /**
     * 查询任务状态。
     *
     * @param taskId 任务 ID
     * @return 任务状态
     */
    public ParseTaskStatus queryTask(String taskId) {
        return requireRecord(taskId).getStatusSnapshot();
    }

    /**
     * 查询任务聚合信息。
     *
     * @param taskId 任务 ID
     * @return 聚合信息
     */
    public ParseTaskInfo queryTaskInfo(String taskId) {
        return requireRecord(taskId).getTaskInfoSnapshot();
    }

    /**
     * 获取任务结果。
     *
     * @param taskId 任务 ID
     * @return 任务结果
     */
    public ParseResponse queryResult(String taskId) {
        DocumentAsyncTaskRecord record = requireRecord(taskId);
        ParseTaskStatus status = record.getStatusSnapshot();
        if (!"completed".equalsIgnoreCase(status.getStatus())) {
            throw new DocumentParseException("Document async task is not completed: " + taskId);
        }
        return record.getResult();
    }

    private DocumentAsyncTaskRecord requireRecord(String taskId) {
        if (!StringUtil.hasText(taskId)) {
            throw new IllegalArgumentException("taskId must not be empty");
        }
        DocumentAsyncTaskRecord record = repository.find(taskId);
        if (record == null) {
            throw new DocumentParseException("Document async task not found: " + taskId);
        }
        return record;
    }

    private void markRunning(DocumentAsyncTaskRecord record) {
        ParseTaskStatus status = record.getStatusSnapshot();
        status.setStatus("preparing");
        status.setStartedAt(Instant.now().toString());
        status.setCurrentStage("preparing");
        status.setProgressPercent(0);
        status.setStatusMessage("任务开始执行");
        record.updateStatus(status);
    }

    private static class RepositoryBackedTaskUpdater implements DocumentAsyncTaskUpdater {

        private final DocumentAsyncTaskRecord record;

        private RepositoryBackedTaskUpdater(DocumentAsyncTaskRecord record) {
            this.record = record;
        }

        @Override
        public void update(String stage, Integer progressPercent, Integer processedItems, Integer totalItems, String statusMessage) {
            ParseTaskStatus status = record.getStatusSnapshot();
            status.setStatus("completed".equalsIgnoreCase(stage) ? "completed" : "running");
            status.setCurrentStage(stage);
            status.setProgressPercent(progressPercent);
            status.setProcessedItems(processedItems);
            status.setTotalItems(totalItems);
            status.setStatusMessage(statusMessage);
            record.updateStatus(status);
        }
    }
}
