#!/usr/bin/env python3
# Copyright: 2026, Maximiliano Curia <maxy@debian.org>
#
# License: ISC
#  Permission to use, copy, modify, and/or distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#  .
#  THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
#  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
#  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
#  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
#  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
#  PERFORMANCE OF THIS SOFTWARE.

"""Deletion provenance: a stale paragraph names the deleted file that emptied it.

Unit-level over Copyright.process with the deleted set injected directly (no git
needed): fnmatch of the deleted paths against the stale paragraph's patterns.
"""

from __future__ import annotations

import tempfile
import unittest
from pathlib import Path

from decopy import cmdoptions
from decopy.dep5doc import dep5
from decopy.dep5doc.delta import STALE_PARAGRAPH, DeltaReport
from decopy.fstree import tree

# u*.c stays alive via util.c so only legacy/* is stale.
_COPYRIGHT = """\
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: TODO

Files: u*.c
License: Expat

Files: legacy/*
License: GPL-2+
"""


def _stale_entries(root: Path, deleted: tuple[str, ...] = ()) -> list:
    (root / "util.c").write_text("int x;\n", encoding="utf-8")
    debian = root / "debian"
    debian.mkdir(exist_ok=True)
    (debian / "copyright").write_text(_COPYRIGHT, encoding="utf-8")
    options = cmdoptions.process_options(
        ["--no-progress", "--no-expand-archives", "--root", str(root)]
    )
    filetree = tree.RootInfo.build(options)
    copyright_ = dep5.read_copyright(options)
    report = DeltaReport()
    copyright_.process(filetree, report, deleted)
    return report.by_kind().get(STALE_PARAGRAPH, [])


class DeletionProvenanceTest(unittest.TestCase):
    def test_matching_deleted_path_is_named_as_culprit(self):
        with tempfile.TemporaryDirectory() as tmp:
            entries = _stale_entries(Path(tmp), ("legacy/old.c",))
        self.assertEqual(len(entries), 1)
        self.assertEqual(entries[0].deleted_files, ("legacy/old.c",))

    def test_no_deleted_set_leaves_provenance_none(self):
        with tempfile.TemporaryDirectory() as tmp:
            entries = _stale_entries(Path(tmp))
        self.assertEqual(len(entries), 1)
        self.assertIsNone(entries[0].deleted_files)

    def test_non_matching_deleted_path_leaves_provenance_none(self):
        with tempfile.TemporaryDirectory() as tmp:
            entries = _stale_entries(Path(tmp), ("src/other.c",))
        self.assertEqual(len(entries), 1)
        self.assertIsNone(entries[0].deleted_files)

    def test_multiple_culprits_sorted(self):
        with tempfile.TemporaryDirectory() as tmp:
            entries = _stale_entries(
                Path(tmp), ("legacy/z.c", "legacy/a.c", "src/keep.c")
            )
        self.assertEqual(entries[0].deleted_files, ("legacy/a.c", "legacy/z.c"))
