#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import io
import os
import tempfile
import unittest
from contextlib import redirect_stdout

from common import find_target_items, reverse_items, sort_items


class CommonScriptTest(unittest.TestCase):
    def run_file_op(self, func, input_text, *, input_bytes=None):
        with tempfile.TemporaryDirectory() as tmpdir:
            src = os.path.join(tmpdir, "in.txt")
            dst = os.path.join(tmpdir, "out.txt")

            if input_bytes is not None:
                with open(src, "wb") as f:
                    f.write(input_bytes)
            else:
                with open(src, "w", encoding="utf-8") as f:
                    f.write(input_text)

            func(src, dst)

            with open(dst, "rb") as f:
                return f.read()

    def test_sort_entries(self):
        out = self.run_file_op(sort_items, "b\tB\na\tA\n")
        self.assertEqual(out.decode("utf-8"), "a\tA\nb\tB\n")

    def test_sort_moves_comment_with_following_entry(self):
        out = self.run_file_op(sort_items, "b\tB\n# comment for a\na\tA\n")
        self.assertEqual(
            out.decode("utf-8"),
            "# comment for a\na\tA\nb\tB\n",
        )

    def test_sort_preserves_blank_lines_in_anchored_block(self):
        out = self.run_file_op(sort_items, "b\tB\n\n# comment for a\na\tA\n")
        self.assertEqual(
            out.decode("utf-8"),
            "\n# comment for a\na\tA\nb\tB\n",
        )

    def test_sort_splits_header_from_first_entry_comment(self):
        out = self.run_file_op(
            sort_items,
            "# Header\n\n# comment for b\nb\tB\na\tA\n",
        )
        self.assertEqual(
            out.decode("utf-8"),
            "# Header\n\na\tA\n# comment for b\nb\tB\n",
        )

    def test_sort_keeps_footer_at_end(self):
        out = self.run_file_op(sort_items, "b\tB\na\tA\n\n# footer\n")
        self.assertEqual(
            out.decode("utf-8"),
            "a\tA\nb\tB\n\n# footer\n",
        )

    def test_sort_preserves_missing_final_newline(self):
        out = self.run_file_op(
            sort_items,
            "",
            input_bytes=b"b\tB\na\tA",
        )
        self.assertEqual(out, b"a\tA\nb\tB")

    def test_sort_normalizes_crlf_input(self):
        out = self.run_file_op(
            sort_items,
            "",
            input_bytes=b"b\tB\r\na\tA\r\n",
        )
        self.assertEqual(out, b"a\tA\nb\tB\n")

    def test_reverse_items(self):
        out = self.run_file_op(reverse_items, "A\tx y\nB\tx\n")
        self.assertEqual(
            out.decode("utf-8"),
            "x\tA B\ny\tA\n",
        )

    def test_reverse_items_applies_reverse_preference(self):
        out = self.run_file_op(
            reverse_items,
            "# @reverse-prefer: x B\nA\tx\nB\tx\n",
        )
        self.assertEqual(out.decode("utf-8"), "x\tB A\n")

    def test_reverse_items_uses_key_as_default_reverse_preference(self):
        out = self.run_file_op(
            reverse_items,
            "# @reverse-prefer: x\nx\tx\nA\tx\n",
        )
        self.assertEqual(out.decode("utf-8"), "x\tx A\n")

    def test_reverse_items_rejects_unmatched_reverse_preference(self):
        with self.assertRaises(ValueError):
            self.run_file_op(
                reverse_items,
                "# @reverse-prefer: x C\nA\tx\nB\tx\n",
            )

    def test_find_target_items_matches_values_only(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            src = os.path.join(tmpdir, "in.txt")
            with open(src, "w", encoding="utf-8") as f:
                f.write("foo\tbar baz\n")
                f.write("target\txxx\n")
                f.write("abc\ttarget-value\n")

            buf = io.StringIO()
            with redirect_stdout(buf):
                find_target_items(src, "target")

            self.assertEqual(buf.getvalue(), "abc\ttarget-value\n")


if __name__ == "__main__":
    unittest.main()
