"""Record metadata for the build process."""

from __future__ import annotations

from typing import TYPE_CHECKING

from sphinx.locale import __
from sphinx.util._serialise import stable_hash

if TYPE_CHECKING:
    from collections.abc import Set
    from pathlib import Path

    from sphinx.config import Config, _ConfigRebuild
    from sphinx.util.tags import Tags


class BuildInfo:
    """buildinfo file manipulator.

    HTMLBuilder and its family are storing their own envdata to ``.buildinfo``.
    This class is a manipulator for the file.
    """

    @classmethod
    def load(cls: type[BuildInfo], filename: Path, /) -> BuildInfo:
        content = filename.read_text(encoding='utf-8')
        lines = content.splitlines()

        version = lines[0].rstrip()
        if version != '# Sphinx build info version 1':
            msg = __('failed to read broken build info file (unknown version)')
            raise ValueError(msg)

        if not lines[2].startswith('config: '):
            msg = __('failed to read broken build info file (missing config entry)')
            raise ValueError(msg)
        if not lines[3].startswith('tags: '):
            msg = __('failed to read broken build info file (missing tags entry)')
            raise ValueError(msg)

        build_info = BuildInfo()
        build_info.config_hash = lines[2].removeprefix('config: ').strip()
        build_info.tags_hash = lines[3].removeprefix('tags: ').strip()
        return build_info

    def __init__(
        self,
        config: Config | None = None,
        tags: Tags | None = None,
        config_categories: Set[_ConfigRebuild] = frozenset(),
    ) -> None:
        self.config_hash = ''
        self.tags_hash = ''

        if config:
            values = {c.name: c.value for c in config.filter(config_categories)}
            self.config_hash = stable_hash(values)

        if tags:
            self.tags_hash = stable_hash(sorted(tags))

    def __eq__(self, other: BuildInfo) -> bool:  # type: ignore[override]
        return (
            self.config_hash == other.config_hash and self.tags_hash == other.tags_hash
        )

    def __hash__(self) -> int:
        return hash((self.config_hash, self.tags_hash))

    def dump(self, filename: Path, /) -> None:
        build_info = (
            '# Sphinx build info version 1\n'
            '# This file records the configuration used when building these files. '
            'When it is not found, a full rebuild will be done.\n'
            f'config: {self.config_hash}\n'
            f'tags: {self.tags_hash}\n'
        )
        filename.write_text(build_info, encoding='utf-8')
