using System.IO.Compression;

namespace Shared.Excel;

public sealed class XlsxSafetyInspector
{
    public const long DefaultMaxUncompressedBytes = 250L * 1024 * 1024;
    public const int DefaultMaxEntries = 5_000;

    public void EnsureSafe(byte[] bytes, long maxUncompressedBytes = DefaultMaxUncompressedBytes, int maxEntries = DefaultMaxEntries)
    {
        using var stream = new MemoryStream(bytes, writable: false);
        using var archive = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: false);
        if (archive.Entries.Count == 0 || archive.Entries.Count > maxEntries)
            throw new InvalidDataException("Excel 파일 내부 구조가 비정상적입니다.");

        if (!archive.Entries.Any(x => x.FullName.Equals("[Content_Types].xml", StringComparison.OrdinalIgnoreCase)) ||
            !archive.Entries.Any(x => x.FullName.Equals("xl/workbook.xml", StringComparison.OrdinalIgnoreCase)))
            throw new InvalidDataException("유효한 .xlsx 통합문서가 아닙니다.");

        long total = 0;
        foreach (var entry in archive.Entries)
        {
            total = checked(total + entry.Length);
            if (total > maxUncompressedBytes)
                throw new InvalidDataException("압축 해제된 Excel 데이터가 허용 크기를 초과합니다.");

            // A very small compressed entry expanding to an extreme size is suspicious.
            if (entry.CompressedLength > 0 && entry.Length > 10L * 1024 * 1024 && entry.Length / entry.CompressedLength > 200)
                throw new InvalidDataException("비정상적인 압축률의 Excel 항목이 감지되었습니다.");
        }
    }
}
