#!/usr/bin/env python3
"""Tests for pure functions in generate_build_history.py."""
import re
import unittest
from unittest.mock import patch

from generate_build_history import MAX_BUILDS_PER_PLATFORM, parse_builds, render_entries

LINUX_RE = re.compile(
    r"public_html/builds/(\d{4})/(\d{2})/(\d{2})/(sharedinbox-linux-amd64-(.+)\.tar\.gz)$"
)
APK_RE = re.compile(
    r"public_html/builds/(\d{4})/(\d{2})/(\d{2})/(sharedinbox-mua-(.+)\.apk)$"
)


def _fake_commit_info(hash_val: str):
    return (f"feat: {hash_val}", "2025-05-10T12:00:00Z")


class TestParseBuilds(unittest.TestCase):
    def setUp(self):
        patcher = patch("generate_build_history.get_commit_info", side_effect=_fake_commit_info)
        self.mock_commit = patcher.start()
        self.addCleanup(patcher.stop)

    def test_linux_path_parsed(self):
        paths = ["public_html/builds/2025/05/10/sharedinbox-linux-amd64-abc1234.tar.gz"]
        result = parse_builds(paths, LINUX_RE)
        self.assertIn("2025/05/10", result)
        entry = result["2025/05/10"][0]
        self.assertEqual(entry[0], "abc1234")
        self.assertIn("sharedinbox-linux-amd64-abc1234.tar.gz", entry[1])

    def test_apk_path_parsed(self):
        paths = ["public_html/builds/2025/05/11/sharedinbox-mua-def5678.apk"]
        result = parse_builds(paths, APK_RE)
        self.assertIn("2025/05/11", result)
        entry = result["2025/05/11"][0]
        self.assertEqual(entry[0], "def5678")
        self.assertIn("sharedinbox-mua-def5678.apk", entry[1])

    def test_unexpected_path_skipped(self):
        paths = [
            "public_html/builds/2025/05/10/sharedinbox-linux-amd64-abc1234.tar.gz",
            "public_html/builds/bad-path/other.tar.gz",
        ]
        result = parse_builds(paths, LINUX_RE)
        self.assertEqual(len(result), 1)

    def test_multiple_builds_same_day(self):
        paths = [
            "public_html/builds/2025/05/10/sharedinbox-linux-amd64-aaa0001.tar.gz",
            "public_html/builds/2025/05/10/sharedinbox-linux-amd64-bbb0002.tar.gz",
        ]
        result = parse_builds(paths, LINUX_RE)
        self.assertEqual(len(result["2025/05/10"]), 2)

    def test_limited_to_max_builds(self):
        paths = [
            f"public_html/builds/2025/05/{i:02d}/sharedinbox-linux-amd64-hash{i:03d}.tar.gz"
            for i in range(1, MAX_BUILDS_PER_PLATFORM + 5)
        ]
        result = parse_builds(paths, LINUX_RE)
        total = sum(len(v) for v in result.values())
        self.assertEqual(total, MAX_BUILDS_PER_PLATFORM)

    def test_download_url_contains_date_and_filename(self):
        paths = ["public_html/builds/2025/03/15/sharedinbox-linux-amd64-cafebabe.tar.gz"]
        result = parse_builds(paths, LINUX_RE)
        url = result["2025/03/15"][0][1]
        self.assertIn("/2025/03/15/", url)
        self.assertIn("sharedinbox-linux-amd64-cafebabe.tar.gz", url)
        self.assertTrue(url.startswith("https://"))


class TestRenderEntries(unittest.TestCase):
    def _make_entry(self, hash_val="abc1234", url="https://example.com/file.apk",
                    title="feat: something", dt="2025-05-10T12:00:00Z"):
        return (hash_val, url, title, dt)

    def test_output_contains_title_and_link(self):
        entry = self._make_entry()
        out = render_entries([entry], "Download APK")
        self.assertIn("feat: something", out)
        self.assertIn("Download APK", out)
        self.assertIn("abc1234", out)

    def test_commit_url_uses_hash(self):
        entry = self._make_entry(hash_val="deadbeef")
        out = render_entries([entry], "Download")
        self.assertIn("deadbeef", out)
        self.assertIn("codeberg.org", out)

    def test_datetime_shown_when_present(self):
        entry = self._make_entry(dt="2025-05-10T12:00:00Z")
        out = render_entries([entry], "Download")
        self.assertIn("2025-05-10T12:00:00Z", out)

    def test_datetime_omitted_when_empty(self):
        entry = self._make_entry(dt="")
        out = render_entries([entry], "Download")
        self.assertNotIn(" · ", out)

    def test_multiple_entries_all_rendered(self):
        entries = [self._make_entry(hash_val=f"hash{i}", title=f"commit {i}") for i in range(3)]
        out = render_entries(entries, "Download")
        for i in range(3):
            self.assertIn(f"commit {i}", out)


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