/**
 * 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;

import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;

/**
 * 表示一个链式节点校验结果。
 * 包含校验是否成功、消息说明以及附加的详细信息（如失败字段、原因等）。
 * <p>
 * 实例是不可变的（immutable），线程安全。
 */
public class NodeValidResult implements Serializable {

    private static final long serialVersionUID = 1L;

    public static final NodeValidResult SUCCESS = new NodeValidResult(true, null, null);
    public static final NodeValidResult FAILURE = new NodeValidResult(false, null, null);

    private final boolean success;
    private final String message;
    private final Map<String, Object> details;

    /**
     * 私有构造器，确保通过工厂方法创建实例。
     */
    private NodeValidResult(boolean success, String message, Map<String, Object> details) {
        this.success = success;
        this.message = message;
        // 防御性拷贝，防止外部修改
        this.details = details != null ? Collections.unmodifiableMap(new java.util.HashMap<>(details)) : null;
    }

    /**
     * 获取校验是否成功。
     */
    public boolean isSuccess() {
        return success;
    }

    /**
     * 获取结果消息（可为 null）。
     */
    public String getMessage() {
        return message;
    }

    /**
     * 获取详细信息（如校验失败的字段、原因等），不可变 Map。
     * 如果无详情，则返回 null。
     */
    public Map<String, Object> getDetails() {
        return details;
    }

    // ------------------ 静态工厂方法 ------------------

    /**
     * 创建一个成功的校验结果（无消息、无详情）。
     */
    public static NodeValidResult ok() {
        return SUCCESS;
    }

    /**
     * 创建一个成功的校验结果，附带消息。
     */
    public static NodeValidResult ok(String message) {
        return new NodeValidResult(true, message, null);
    }

    /**
     * 创建一个成功的校验结果，附带消息和详情。
     */
    public static NodeValidResult ok(String message, Map<String, Object> details) {
        return new NodeValidResult(true, message, details);
    }

    /**
     * 创建一个成功的校验结果，支持键值对形式传入 details。
     * <p>
     * 示例：success("验证通过", "userId", 123, "role", "admin")
     *
     * @param message 消息
     * @param kvPairs 键值对（必须成对：key1, value1, key2, value2...）
     * @return ChainNodeValidResult
     * @throws IllegalArgumentException 如果 kvPairs 数量为奇数
     */
    public static NodeValidResult ok(String message, Object... kvPairs) {
        Map<String, Object> details = toMapFromPairs(kvPairs);
        return new NodeValidResult(true, message, details);
    }


    /**
     * 创建一个失败的校验结果（无消息、无详情）。
     */
    public static NodeValidResult fail() {
        return FAILURE;
    }

    /**
     * 创建一个失败的校验结果，仅包含消息。
     */
    public static NodeValidResult fail(String message) {
        return new NodeValidResult(false, message, null);
    }

    /**
     * 创建一个失败的校验结果，包含消息和详情。
     */
    public static NodeValidResult fail(String message, Map<String, Object> details) {
        return new NodeValidResult(false, message, details);
    }

    /**
     * 创建一个失败的校验结果，支持键值对形式传入 details。
     * <p>
     * 示例：fail("验证失败", "field", "email", "reason", "格式错误")
     */
    public static NodeValidResult fail(String message, Object... kvPairs) {
        Map<String, Object> details = toMapFromPairs(kvPairs);
        return new NodeValidResult(false, message, details);
    }

    /**
     * 快捷方法：创建包含字段错误的失败结果。
     * 适用于表单/参数校验场景。
     *
     * @param field  错误字段名
     * @param reason 错误原因
     * @return 失败结果
     */
    public static NodeValidResult failOnField(String field, String reason) {
        Map<String, Object> details = Collections.singletonMap("fieldError", field + ": " + reason);
        return fail(reason, details);
    }

    /**
     * 快捷方法：基于布尔值返回成功或失败结果。
     *
     * @param condition     条件
     * @param messageIfFail 条件不满足时的消息
     * @return 根据条件返回对应结果
     */
    public static NodeValidResult require(boolean condition, String messageIfFail) {
        return condition ? ok() : fail(messageIfFail);
    }


    private static Map<String, Object> toMapFromPairs(Object... kvPairs) {
        if (kvPairs == null || kvPairs.length == 0) {
            return null;
        }

        if (kvPairs.length % 2 != 0) {
            throw new IllegalArgumentException("kvPairs must be even-sized: key1, value1, key2, value2...");
        }

        Map<String, Object> map = new java.util.HashMap<>();
        for (int i = 0; i < kvPairs.length; i += 2) {
            Object key = kvPairs[i];
            Object value = kvPairs[i + 1];

            if (!(key instanceof String)) {
                throw new IllegalArgumentException("Key must be a String, but got: " + key);
            }

            map.put((String) key, value);
        }
        return Collections.unmodifiableMap(map);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof NodeValidResult)) return false;
        NodeValidResult that = (NodeValidResult) o;
        return success == that.success &&
            Objects.equals(message, that.message) &&
            Objects.equals(details, that.details);
    }

    @Override
    public int hashCode() {
        return Objects.hash(success, message, details);
    }

    @Override
    public String toString() {
        return "ChainNodeValidResult{" +
            "success=" + success +
            ", message='" + message + '\'' +
            ", details=" + details +
            '}';
    }
}
