using System;

namespace VMdemo.Core
{
    public static class ConfigValidator
    {
        public readonly struct DerivedConfig
        {
            public DerivedConfig(ulong pageSizeBytes, ulong physicalMemoryBytes, int offsetBits, int vpnBits, ulong frameCount)
            {
                PageSizeBytes = pageSizeBytes;
                PhysicalMemoryBytes = physicalMemoryBytes;
                OffsetBits = offsetBits;
                VpnBits = vpnBits;
                FrameCount = frameCount;
            }

            public ulong PageSizeBytes { get; }
            public ulong PhysicalMemoryBytes { get; }
            public int OffsetBits { get; }
            public int VpnBits { get; }
            public ulong FrameCount { get; }
        }

        public static bool TryValidate(SimulationConfig config, out string errorMessage)
        {
            return TryValidateAndBuildDerived(config, out _, out errorMessage);
        }

        public static bool TryValidateAndBuildDerived(
            SimulationConfig config,
            out DerivedConfig derived,
            out string errorMessage)
        {
            derived = default;

            if (config == null)
            {
                errorMessage = "配置不能为空。";
                return false;
            }

            if (config.vaBits != 32 && config.vaBits != 48 && config.vaBits != 64)
            {
                errorMessage = "vaBits 仅支持 32、48、64。";
                return false;
            }

            if (config.pageSizeKB <= 0)
            {
                errorMessage = "pageSizeKB 必须是正整数。";
                return false;
            }

            if (!IsPowerOfTwo((ulong)config.pageSizeKB))
            {
                errorMessage = "pageSizeKB 必须是 2 的幂（2^n KB）。";
                return false;
            }

            if (config.physicalMemoryMB <= 0)
            {
                errorMessage = "physicalMemoryMB 必须是正整数。";
                return false;
            }

            if (config.tlbEntries <= 0)
            {
                errorMessage = "tlbEntries 必须是正整数。";
                return false;
            }

            if (config.accessCount <= 0)
            {
                errorMessage = "accessCount 必须是正整数。";
                return false;
            }

            if (config.pageFaultPenalty <= 0)
            {
                errorMessage = "pageFaultPenalty 必须是正整数。";
                return false;
            }

            var pageSizeBytes = config.PageSizeBytes;
            if (!TryGetLog2(pageSizeBytes, out var offsetBits))
            {
                errorMessage = "pageSizeKB 必须对应可计算的 2 的幂字节数。";
                return false;
            }

            if (offsetBits >= config.vaBits)
            {
                errorMessage =
                    $"offsetBits 必须小于 vaBits，当前 offsetBits={offsetBits}，vaBits={config.vaBits}。";
                return false;
            }

            var frameCount = config.FrameCount;
            if (frameCount < 1UL)
            {
                errorMessage =
                    $"frameCount 必须 >= 1，当前 frameCount={frameCount}。请增大 physicalMemoryMB 或减小 pageSizeKB。";
                return false;
            }

            derived = new DerivedConfig(
                pageSizeBytes,
                config.PhysicalMemoryBytes,
                offsetBits,
                config.vaBits - offsetBits,
                frameCount);

            errorMessage = string.Empty;
            return true;
        }

        private static bool IsPowerOfTwo(ulong value)
        {
            return value != 0UL && (value & (value - 1UL)) == 0UL;
        }

        private static bool TryGetLog2(ulong value, out int bits)
        {
            bits = -1;
            if (!IsPowerOfTwo(value))
            {
                return false;
            }

            bits = 0;
            while (value > 1UL)
            {
                value >>= 1;
                bits++;
            }

            return true;
        }
    }
}
