"""Materialize exact UX successor source qualification evidence."""

from __future__ import annotations

import argparse
import difflib
import hashlib
import os
import shutil
from pathlib import Path


def _sha256(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for chunk in iter(lambda: handle.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


def _lines(path: Path) -> tuple[str, ...]:
    return tuple(
        line
        for line in path.read_text(encoding="utf-8").splitlines()
        if line.strip()
    )


def _patch_relative(line: str) -> Path:
    _digest, absolute = line.split("  ", maxsplit=1)
    marker = "/patch-tree/"
    if marker not in absolute:
        raise ValueError("prior patch-tree entry is invalid")
    return Path(absolute.split(marker, maxsplit=1)[1])


def _exact_relative(line: str) -> Path:
    relative, _digest = line.rsplit("  ", maxsplit=1)
    path = Path(relative)
    if path.is_absolute() or ".." in path.parts:
        raise ValueError("prior exact-source entry is invalid")
    return path


def _private_write(path: Path, content: str) -> None:
    _ = path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    _ = path.write_text(content, encoding="utf-8")
    path.chmod(0o600)


def qualify(
    *,
    source_root: Path,
    prior_candidate: Path,
    output: Path,
) -> None:
    source_root = source_root.resolve()
    prior_candidate = prior_candidate.resolve()
    output = output.resolve()
    prior_inputs = prior_candidate / "inputs"
    if output.exists():
        shutil.rmtree(output)
    output.mkdir(parents=True, mode=0o700)

    patch_relatives = tuple(
        _patch_relative(line)
        for line in _lines(prior_inputs / "v17-patch-tree.sha256")
    )
    exact_relatives = tuple(
        _exact_relative(line)
        for line in _lines(prior_inputs / "v17-exact-source-set.sha256")
    )
    if len(set(patch_relatives)) != len(patch_relatives):
        raise ValueError("duplicate patch-tree source path")
    if len(set(exact_relatives)) != len(exact_relatives):
        raise ValueError("duplicate exact-source path")

    patch_lines: list[str] = []
    diff_lines = [
        "NutriCoach customer UX successor qualification diff",
        "",
    ]
    changed = 0
    for relative in patch_relatives:
        current = source_root / relative
        prior = prior_candidate / "snapshot" / "source" / relative
        if not current.is_file() or not prior.is_file():
            raise FileNotFoundError(relative)
        destination = output / "patch-tree" / relative
        destination.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
        _ = shutil.copy2(current, destination)
        destination.chmod(0o600)
        patch_lines.append(f"{_sha256(destination)}  {destination}")
        if _sha256(current) == _sha256(prior):
            continue
        changed += 1
        diff_lines.extend(
            difflib.unified_diff(
                prior.read_text(encoding="utf-8").splitlines(),
                current.read_text(encoding="utf-8").splitlines(),
                fromfile=f"r39/{relative.as_posix()}",
                tofile=f"ux-successor/{relative.as_posix()}",
                lineterm="",
            )
        )
    if changed == 0:
        raise ValueError("UX successor qualification contains no source change")

    exact_lines: list[str] = []
    for relative in exact_relatives:
        current = source_root / relative
        if not current.is_file():
            raise FileNotFoundError(relative)
        exact_lines.append(f"{relative.as_posix()}  {_sha256(current)}")

    patch_manifest = output / "patch-tree.sha256"
    exact_manifest = output / "exact-current-source-set.final.sha256"
    sandbox_diff = output / "sandbox.diff"
    _private_write(patch_manifest, "\n".join(patch_lines) + "\n")
    _private_write(exact_manifest, "\n".join(exact_lines) + "\n")
    _private_write(sandbox_diff, "\n".join(diff_lines) + "\n")

    evidence = output / "evidence-files.sha256"
    _private_write(
        evidence,
        "\n".join(
            f"{_sha256(path)}  {path}"
            for path in (exact_manifest, patch_manifest, sandbox_diff)
        )
        + "\n",
    )
    for directory, subdirectories, filenames in os.walk(output):
        Path(directory).chmod(0o700)
        for subdirectory in subdirectories:
            (Path(directory) / subdirectory).chmod(0o700)
        for filename in filenames:
            (Path(directory) / filename).chmod(0o600)


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    _ = parser.add_argument("--source-root", required=True, type=Path)
    _ = parser.add_argument("--prior-candidate", required=True, type=Path)
    _ = parser.add_argument("--output", required=True, type=Path)
    args = parser.parse_args(namespace=_Arguments())
    qualify(
        source_root=args.source_root,
        prior_candidate=args.prior_candidate,
        output=args.output,
    )
    return 0


class _Arguments(argparse.Namespace):
    source_root: Path = Path()
    prior_candidate: Path = Path()
    output: Path = Path()


if __name__ == "__main__":
    raise SystemExit(main())
