package com.easyagents.skill.model;

import com.easyagents.skill.exception.SkillValidationException;

import java.io.Serial;
import java.io.Serializable;

/**
 * Skill 包读取安全限额；调用方只能在底层硬上限内收紧或调整。
 */
public final class SkillPackageLimits implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    private static final int HARD_MAX_ENTRY_COUNT = 10_000;
    private static final long HARD_MAX_TEXT_FILE_BYTES = 8L * 1024 * 1024;
    private static final long HARD_MAX_BINARY_FILE_BYTES = 200L * 1024 * 1024;
    private static final long HARD_MAX_TOTAL_BYTES = 512L * 1024 * 1024;
    private static final long HARD_MAX_COMPRESSED_BYTES = 512L * 1024 * 1024;
    private static final int HARD_MAX_PATH_LENGTH = 1_024;
    private static final int HARD_MAX_PATH_DEPTH = 32;
    private static final double HARD_MAX_COMPRESSION_RATIO = 200D;
    private static final long HARD_MAX_FRONTMATTER_BYTES = 256L * 1024;
    private static final int HARD_MAX_YAML_ALIASES = 50;
    private static final int HARD_MAX_YAML_DEPTH = 20;
    private static final int HARD_MAX_YAML_CODE_POINTS = 262_144;

    private final int maxEntryCount;
    private final long maxTextFileBytes;
    private final long maxBinaryFileBytes;
    private final long maxTotalUncompressedBytes;
    private final long maxCompressedPackageBytes;
    private final int maxPathLength;
    private final int maxPathDepth;
    private final double maxCompressionRatio;
    private final long maxFrontmatterBytes;
    private final int maxYamlAliases;
    private final int maxYamlDepth;
    private final int maxYamlCodePoints;

    private SkillPackageLimits(Builder builder) {
        maxEntryCount = positive(builder.maxEntryCount, HARD_MAX_ENTRY_COUNT, "maxEntryCount");
        maxTextFileBytes = positive(builder.maxTextFileBytes, HARD_MAX_TEXT_FILE_BYTES, "maxTextFileBytes");
        maxBinaryFileBytes = positive(builder.maxBinaryFileBytes, HARD_MAX_BINARY_FILE_BYTES,
                "maxBinaryFileBytes");
        maxTotalUncompressedBytes = positive(builder.maxTotalUncompressedBytes, HARD_MAX_TOTAL_BYTES,
                "maxTotalUncompressedBytes");
        maxCompressedPackageBytes = positive(builder.maxCompressedPackageBytes, HARD_MAX_COMPRESSED_BYTES,
                "maxCompressedPackageBytes");
        maxPathLength = positive(builder.maxPathLength, HARD_MAX_PATH_LENGTH, "maxPathLength");
        maxPathDepth = positive(builder.maxPathDepth, HARD_MAX_PATH_DEPTH, "maxPathDepth");
        maxCompressionRatio = positive(builder.maxCompressionRatio, HARD_MAX_COMPRESSION_RATIO,
                "maxCompressionRatio");
        maxFrontmatterBytes = positive(builder.maxFrontmatterBytes, HARD_MAX_FRONTMATTER_BYTES,
                "maxFrontmatterBytes");
        maxYamlAliases = nonNegative(builder.maxYamlAliases, HARD_MAX_YAML_ALIASES, "maxYamlAliases");
        maxYamlDepth = positive(builder.maxYamlDepth, HARD_MAX_YAML_DEPTH, "maxYamlDepth");
        maxYamlCodePoints = positive(builder.maxYamlCodePoints, HARD_MAX_YAML_CODE_POINTS,
                "maxYamlCodePoints");
        if (maxTextFileBytes > maxTotalUncompressedBytes || maxBinaryFileBytes > maxTotalUncompressedBytes) {
            throw new SkillValidationException("Single-file limits cannot exceed the total uncompressed limit.");
        }
    }

    /**
     * 创建默认限额。
     *
     * @return 默认限额
     */
    public static SkillPackageLimits defaults() {
        return builder().build();
    }

    /**
     * 创建限额构建器。
     *
     * @return 限额构建器
     */
    public static Builder builder() {
        return new Builder();
    }

    /** @return 最大 ZIP entry 数 */
    public int getMaxEntryCount() {
        return maxEntryCount;
    }

    /** @return 单文本文件最大字节数 */
    public long getMaxTextFileBytes() {
        return maxTextFileBytes;
    }

    /** @return 单二进制文件最大字节数 */
    public long getMaxBinaryFileBytes() {
        return maxBinaryFileBytes;
    }

    /** @return 包总未压缩最大字节数 */
    public long getMaxTotalUncompressedBytes() {
        return maxTotalUncompressedBytes;
    }

    /** @return 输入 ZIP 最大压缩字节数 */
    public long getMaxCompressedPackageBytes() {
        return maxCompressedPackageBytes;
    }

    /** @return 单路径最大字符数 */
    public int getMaxPathLength() {
        return maxPathLength;
    }

    /** @return 最大目录深度 */
    public int getMaxPathDepth() {
        return maxPathDepth;
    }

    /** @return 单 entry 最大压缩比 */
    public double getMaxCompressionRatio() {
        return maxCompressionRatio;
    }

    /** @return frontmatter 最大字节数 */
    public long getMaxFrontmatterBytes() {
        return maxFrontmatterBytes;
    }

    /** @return YAML collection 最大 alias 数 */
    public int getMaxYamlAliases() {
        return maxYamlAliases;
    }

    /** @return YAML 最大嵌套深度 */
    public int getMaxYamlDepth() {
        return maxYamlDepth;
    }

    /** @return YAML 最大 Unicode code point 数 */
    public int getMaxYamlCodePoints() {
        return maxYamlCodePoints;
    }

    private static int positive(int value, int hardMax, String name) {
        if (value <= 0 || value > hardMax) {
            throw new SkillValidationException(name + " must be between 1 and " + hardMax + ".");
        }
        return value;
    }

    private static int nonNegative(int value, int hardMax, String name) {
        if (value < 0 || value > hardMax) {
            throw new SkillValidationException(name + " must be between 0 and " + hardMax + ".");
        }
        return value;
    }

    private static long positive(long value, long hardMax, String name) {
        if (value <= 0 || value > hardMax) {
            throw new SkillValidationException(name + " must be between 1 and " + hardMax + ".");
        }
        return value;
    }

    private static double positive(double value, double hardMax, String name) {
        if (!Double.isFinite(value) || value <= 0D || value > hardMax) {
            throw new SkillValidationException(name + " must be between 0 and " + hardMax + ".");
        }
        return value;
    }

    /**
     * Skill 包限额构建器。
     */
    public static final class Builder {

        private int maxEntryCount = 2_000;
        private long maxTextFileBytes = 2L * 1024 * 1024;
        private long maxBinaryFileBytes = 50L * 1024 * 1024;
        private long maxTotalUncompressedBytes = 200L * 1024 * 1024;
        private long maxCompressedPackageBytes = 100L * 1024 * 1024;
        private int maxPathLength = 512;
        private int maxPathDepth = 16;
        private double maxCompressionRatio = 100D;
        private long maxFrontmatterBytes = 64L * 1024;
        private int maxYamlAliases = 10;
        private int maxYamlDepth = 10;
        private int maxYamlCodePoints = 65_536;

        private Builder() {
        }

        /** @param value 最大 entry 数 @return 当前构建器 */
        public Builder maxEntryCount(int value) {
            maxEntryCount = value;
            return this;
        }

        /** @param value 单文本文件最大字节数 @return 当前构建器 */
        public Builder maxTextFileBytes(long value) {
            maxTextFileBytes = value;
            return this;
        }

        /** @param value 单二进制文件最大字节数 @return 当前构建器 */
        public Builder maxBinaryFileBytes(long value) {
            maxBinaryFileBytes = value;
            return this;
        }

        /** @param value 包总未压缩最大字节数 @return 当前构建器 */
        public Builder maxTotalUncompressedBytes(long value) {
            maxTotalUncompressedBytes = value;
            return this;
        }

        /** @param value 输入 ZIP 最大压缩字节数 @return 当前构建器 */
        public Builder maxCompressedPackageBytes(long value) {
            maxCompressedPackageBytes = value;
            return this;
        }

        /** @param value 单路径最大字符数 @return 当前构建器 */
        public Builder maxPathLength(int value) {
            maxPathLength = value;
            return this;
        }

        /** @param value 最大目录深度 @return 当前构建器 */
        public Builder maxPathDepth(int value) {
            maxPathDepth = value;
            return this;
        }

        /** @param value 单 entry 最大压缩比 @return 当前构建器 */
        public Builder maxCompressionRatio(double value) {
            maxCompressionRatio = value;
            return this;
        }

        /** @param value frontmatter 最大字节数 @return 当前构建器 */
        public Builder maxFrontmatterBytes(long value) {
            maxFrontmatterBytes = value;
            return this;
        }

        /** @param value YAML alias 最大数量 @return 当前构建器 */
        public Builder maxYamlAliases(int value) {
            maxYamlAliases = value;
            return this;
        }

        /** @param value YAML 最大嵌套深度 @return 当前构建器 */
        public Builder maxYamlDepth(int value) {
            maxYamlDepth = value;
            return this;
        }

        /** @param value YAML 最大 code point 数 @return 当前构建器 */
        public Builder maxYamlCodePoints(int value) {
            maxYamlCodePoints = value;
            return this;
        }

        /**
         * 构建并校验限额。
         *
         * @return 不可变限额
         */
        public SkillPackageLimits build() {
            return new SkillPackageLimits(this);
        }
    }
}
