#!/usr/bin/env python3
"""Compute and write a Seamless directory index and checksum files."""

import argparse
import os
import sys

import seamless
from seamless import Checksum
from seamless.checksum.calculate_checksum import calculate_checksum
from seamless.checksum.serialize import serialize_sync as serialize


def _calculate_file_checksum(filename: str) -> str:
    with open(filename, "rb") as f:
        buffer = f.read()
    return calculate_checksum(buffer)


def _write_checksum(filename: str, checksum: str) -> None:
    checksum = Checksum(checksum)
    filename2 = filename
    if filename.endswith(".INDEX"):
        filename2 = os.path.splitext(filename)[0]
    with open(filename2 + ".CHECKSUM", "w") as f:
        f.write(checksum.hex() + "\n")


def _build_directory_index(dirname: str) -> tuple[bytes, str]:
    deepfolder = {}
    for dirpath, _, filenames in os.walk(dirname):
        assert dirpath.startswith(dirname), (dirpath, dirname)
        dirtail = dirpath[len(dirname) + 1 :]
        for filename in filenames:
            full_filename = os.path.join(dirpath, filename)
            mapped_filename = os.path.join(dirtail, filename)
            deepfolder[mapped_filename] = _calculate_file_checksum(full_filename)
    index_buffer = serialize(deepfolder, "plain")
    index_checksum = calculate_checksum(index_buffer)
    return index_buffer, index_checksum


def _main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(
        prog="seamless-checksum-index",
        description="Write a .INDEX and .CHECKSUM for a directory",
    )
    parser.add_argument("directory", help="Path to the directory to index")
    args = parser.parse_args(argv)

    dirname = args.directory.rstrip(os.sep)
    if not os.path.isdir(dirname):
        print(f"Error: '{dirname}' is not a directory", file=sys.stderr)
        return 1

    try:
        index_buffer, index_checksum = _build_directory_index(dirname)
        with open(dirname + ".INDEX", "wb") as f:
            f.write(index_buffer)
        _write_checksum(dirname, index_checksum)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        return 1
    return 0


def main(argv: list[str] | None = None) -> int:
    try:
        return _main(argv)
    finally:
        seamless.close()


if __name__ == "__main__":
    sys.exit(main())
