/**
 * Copyright (c) 2025-2026, Michael Yang 杨福海 (fuhai999@gmail.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.easyagents.flow.core.chain.runtime;

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;

public class Trigger implements Serializable {
    private static final long serialVersionUID = 3165037658498721088L;

    private String id;
    private String stateInstanceId;
    private String edgeId;
    private String nodeId; // 可以为 null，代表触发整个 chain
    private TriggerType type;
    private long triggerAt; // epoch ms
    /**
     * 当前运行时分配的触发器认领代际。
     *
     * <p>字段名为兼容既有序列化数据保留。分布式仓储在触发器认领成功时分配，
     * 并与该触发器租约共同续期和失效；该值不代表实例锁 fencing token。</p>
     */
    private long fencingToken;
    /**
     * 创建派生触发器时必须仍然有效的父触发器 fencing token。
     */
    private long requiredFencingToken;
    /**
     * 创建派生触发器时必须仍然有效的父实例锁 fencing token。
     */
    private long requiredLockFencingToken;
    /**
     * 创建派生触发器时必须仍然有效的父触发器 claim ID。
     */
    private String requiredFencingClaimId;
    /**
     * 基础设施投递失败次数，不占用业务节点重试次数。
     */
    private int deliveryAttempt;
    /**
     * 已完成业务终态收敛、等待可靠写入死信的标记。
     */
    private boolean deadLetterPending;
    /**
     * 待写入死信的稳定失败原因。
     */
    private String deadLetterReason;
    /**
     * 跨重试保持不变的逻辑执行 ID，用于副作用幂等键。
     */
    private String logicalExecutionId;
    /**
     * 可选执行通道，用于把会同步等待的子工作流与普通节点工作线程隔离。
     */
    private String executionLane;
    /**
     * 首个稳定入口意图携带的初始变量。
     *
     * <p>仅用于实例仍处于 READY 时的崩溃恢复；正常启动提交后，运行时变量仍以
     * {@code ChainState.memory} 为唯一业务数据源。</p>
     */
    private Map<String, Object> startVariables;
    private Map<String, LoopCursor> loopCursors;

    public Trigger() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }


    public String getStateInstanceId() {
        return stateInstanceId;
    }

    public void setStateInstanceId(String stateInstanceId) {
        this.stateInstanceId = stateInstanceId;
    }

    public String getEdgeId() {
        return edgeId;
    }

    public void setEdgeId(String edgeId) {
        this.edgeId = edgeId;
    }

    public String getNodeId() {
        return nodeId;
    }

    public void setNodeId(String nodeId) {
        this.nodeId = nodeId;
    }

    public TriggerType getType() {
        return type;
    }

    public void setType(TriggerType type) {
        this.type = type;
    }

    public long getTriggerAt() {
        return triggerAt;
    }

    public void setTriggerAt(long triggerAt) {
        this.triggerAt = triggerAt;
    }

    /**
     * 获取当前节点逻辑执行 ID。
     *
     * @return 跨重试保持不变的逻辑执行 ID
     */
    public String getLogicalExecutionId() {
        return logicalExecutionId;
    }

    /**
     * 设置当前节点逻辑执行 ID。
     *
     * @param logicalExecutionId 跨重试保持不变的逻辑执行 ID
     */
    public void setLogicalExecutionId(String logicalExecutionId) {
        this.logicalExecutionId = logicalExecutionId;
    }

    /**
     * 获取执行通道。
     *
     * @return 通道名；{@code null} 表示默认通道
     */
    public String getExecutionLane() {
        return executionLane;
    }

    /**
     * 设置执行通道。
     *
     * @param executionLane 通道名
     */
    public void setExecutionLane(String executionLane) {
        this.executionLane = executionLane;
    }

    /**
     * 获取崩溃恢复所需的初始变量。
     *
     * @return 初始变量快照；未携带时为 {@code null}
     */
    public Map<String, Object> getStartVariables() {
        return startVariables;
    }

    /**
     * 设置崩溃恢复所需的初始变量。
     *
     * @param startVariables 初始变量；仅首个稳定入口意图需要携带
     */
    public void setStartVariables(Map<String, Object> startVariables) {
        this.startVariables = startVariables == null
                ? null
                : new LinkedHashMap<>(startVariables);
    }

    /**
     * 获取本次认领代际。
     *
     * @return 单触发器认领代际；未认领时为 {@code 0}
     */
    public long getFencingToken() {
        return fencingToken;
    }

    /**
     * 设置本次认领代际。
     *
     * @param fencingToken 单触发器认领代际
     */
    public void setFencingToken(long fencingToken) {
        this.fencingToken = fencingToken;
    }

    /**
     * 获取保存派生触发器所依赖的父实例锁 fencing token。
     *
     * @return 父实例锁 token；无锁约束时为 {@code 0}
     */
    public long getRequiredLockFencingToken() {
        return requiredLockFencingToken;
    }

    /**
     * 设置保存派生触发器所依赖的父实例锁 fencing token。
     *
     * @param requiredLockFencingToken 父实例锁 token
     */
    public void setRequiredLockFencingToken(long requiredLockFencingToken) {
        this.requiredLockFencingToken = requiredLockFencingToken;
    }

    /**
     * 获取保存派生触发器所依赖的父 fencing token。
     *
     * @return 父 fencing token；无父认领约束时为 {@code 0}
     */
    public long getRequiredFencingToken() {
        return requiredFencingToken;
    }

    /**
     * 设置保存派生触发器所依赖的父 fencing token。
     *
     * @param requiredFencingToken 父 fencing token
     */
    public void setRequiredFencingToken(long requiredFencingToken) {
        this.requiredFencingToken = requiredFencingToken;
    }

    /**
     * 获取保存派生触发器所依赖的父 claim ID。
     *
     * @return 父触发器 ID；无父认领约束时为 {@code null}
     */
    public String getRequiredFencingClaimId() {
        return requiredFencingClaimId;
    }

    /**
     * 设置保存派生触发器所依赖的父 claim ID。
     *
     * @param requiredFencingClaimId 父触发器 ID
     */
    public void setRequiredFencingClaimId(String requiredFencingClaimId) {
        this.requiredFencingClaimId = requiredFencingClaimId;
    }

    /**
     * 获取基础设施投递失败次数。
     *
     * @return 失败次数
     */
    public int getDeliveryAttempt() {
        return deliveryAttempt;
    }

    /**
     * 设置基础设施投递失败次数。
     *
     * @param deliveryAttempt 失败次数
     */
    public void setDeliveryAttempt(int deliveryAttempt) {
        this.deliveryAttempt = deliveryAttempt;
    }

    /**
     * 判断触发器是否正在补写死信终态。
     *
     * @return 等待死信持久化时为 {@code true}
     */
    public boolean isDeadLetterPending() {
        return deadLetterPending;
    }

    /**
     * 设置死信补写标记。
     *
     * @param deadLetterPending 是否等待死信持久化
     */
    public void setDeadLetterPending(boolean deadLetterPending) {
        this.deadLetterPending = deadLetterPending;
    }

    /**
     * 获取稳定死信原因。
     *
     * @return 死信原因
     */
    public String getDeadLetterReason() {
        return deadLetterReason;
    }

    /**
     * 设置稳定死信原因。
     *
     * @param deadLetterReason 死信原因
     */
    public void setDeadLetterReason(String deadLetterReason) {
        this.deadLetterReason = deadLetterReason;
    }

    /**
     * 获取触发器携带的循环代际游标。
     *
     * @return 循环节点 ID 到游标的映射
     */
    public Map<String, LoopCursor> getLoopCursors() {
        if (loopCursors == null) {
            loopCursors = new LinkedHashMap<>();
        }
        return loopCursors;
    }

    /**
     * 设置循环代际游标。
     *
     * @param loopCursors 循环节点 ID 到游标的映射
     */
    public void setLoopCursors(Map<String, LoopCursor> loopCursors) {
        this.loopCursors = loopCursors;
    }

    /**
     * 循环分支代际游标，用于拒绝过期或重复的父节点回调。
     */
    public static class LoopCursor implements Serializable {
        private static final long serialVersionUID = 1L;

        private String resultId;
        private int iterationIndex;
        private String branchId;

        public LoopCursor() {
        }

        /**
         * 创建循环游标。
         *
         * @param resultId 循环代际 ID
         * @param iterationIndex 迭代序号
         * @param branchId 直属分支 ID
         */
        public LoopCursor(String resultId, int iterationIndex, String branchId) {
            this.resultId = resultId;
            this.iterationIndex = iterationIndex;
            this.branchId = branchId;
        }

        public String getResultId() {
            return resultId;
        }

        public void setResultId(String resultId) {
            this.resultId = resultId;
        }

        public int getIterationIndex() {
            return iterationIndex;
        }

        public void setIterationIndex(int iterationIndex) {
            this.iterationIndex = iterationIndex;
        }

        public String getBranchId() {
            return branchId;
        }

        public void setBranchId(String branchId) {
            this.branchId = branchId;
        }
    }

    @Override
    public String toString() {
        return "Trigger{" +
                "id='" + id + '\'' +
                ", stateInstanceId='" + stateInstanceId + '\'' +
                ", edgeId='" + edgeId + '\'' +
                ", nodeId='" + nodeId + '\'' +
                ", type=" + type +
                ", triggerAt=" + triggerAt +
                '}';
    }
}
