package com.easyagents.skill.validation;

import com.easyagents.skill.exception.SkillValidationException;

import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Skill 结构化校验报告。
 */
public final class SkillValidationReport implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    private final List<SkillValidationIssue> issues = new ArrayList<>();

    /**
     * 添加校验问题。
     *
     * @param issue 校验问题
     * @return 当前报告
     */
    public SkillValidationReport add(SkillValidationIssue issue) {
        if (issue != null) {
            issues.add(issue);
        }
        return this;
    }

    /**
     * 合并其他报告。
     *
     * @param report 其他报告
     * @return 当前报告
     */
    public SkillValidationReport merge(SkillValidationReport report) {
        if (report != null) {
            issues.addAll(report.issues);
        }
        return this;
    }

    /**
     * 获取不可变问题列表。
     *
     * @return 问题列表
     */
    public List<SkillValidationIssue> getIssues() {
        return Collections.unmodifiableList(issues);
    }

    /**
     * 判断是否存在错误。
     *
     * @return 存在 ERROR 时为 true
     */
    public boolean hasErrors() {
        return issues.stream().anyMatch(issue -> issue.getSeverity() == SkillValidationSeverity.ERROR);
    }

    /**
     * 判断报告是否为空。
     *
     * @return 没有问题时为 true
     */
    public boolean isEmpty() {
        return issues.isEmpty();
    }

    /**
     * 错误存在时抛出包含完整报告的异常。
     *
     * @throws SkillValidationException 校验报告包含错误
     */
    public void throwIfInvalid() {
        if (hasErrors()) {
            SkillValidationIssue first = issues.stream()
                    .filter(issue -> issue.getSeverity() == SkillValidationSeverity.ERROR)
                    .findFirst()
                    .orElseThrow();
            throw new SkillValidationException(first.getCode(), first.getPath(), first.getLine(),
                    first.getColumn(), first.getMessage(), null, this);
        }
    }
}
