"""Parse HashCache.dat sitting beside PathOfExile.exe (integrity of loose binaries, not GGPK)."""
from __future__ import annotations

import struct
from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path


@dataclass(frozen=True)
class HashCacheRecord:
    name: str
    filetime: int
    size: int
    sha256: bytes

    @property
    def mtime_utc(self) -> datetime:
        # Windows FILETIME: 100ns since 1601-01-01
        unix = (self.filetime / 10_000_000) - 11644473600
        return datetime.fromtimestamp(unix, tz=timezone.utc)


def parse_hashcache(path: str | Path) -> list[HashCacheRecord]:
    data = Path(path).read_bytes()
    if len(data) < 4:
        raise ValueError("HashCache.dat too small")
    count = struct.unpack_from("<I", data, 0)[0]
    pos = 4
    records: list[HashCacheRecord] = []
    for _ in range(count):
        if pos + 4 > len(data):
            raise ValueError("HashCache.dat truncated while reading name length")
        nchars = struct.unpack_from("<I", data, pos)[0]
        pos += 4
        nbytes = nchars * 2
        if pos + nbytes + 8 + 4 + 32 > len(data):
            raise ValueError("HashCache.dat truncated while reading record")
        name = data[pos : pos + nbytes].decode("utf-16le", "replace").rstrip("\x00")
        pos += nbytes
        filetime = struct.unpack_from("<Q", data, pos)[0]
        pos += 8
        size = struct.unpack_from("<I", data, pos)[0]
        pos += 4
        sha = data[pos : pos + 32]
        pos += 32
        records.append(HashCacheRecord(name=name, filetime=filetime, size=size, sha256=sha))
    return records
