import unittest

from fetch_latest_long_episode import PodcastFetchError, find_latest_episode_over_2h, parse_duration, sanitize_filename


SAMPLE_RSS = """<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  <channel>
    <item>
      <title>Short episode</title>
      <pubDate>Mon, 6 Jul 2026 11:00:00 +0000</pubDate>
      <enclosure url="https://example.com/short.mp3" type="audio/mpeg" />
      <itunes:duration>01:59:59</itunes:duration>
    </item>
    <item>
      <title>Latest long episode</title>
      <pubDate>Mon, 6 Jul 2026 12:00:00 +0000</pubDate>
      <enclosure url="https://example.com/latest.mp3" type="audio/mpeg" />
      <itunes:duration>02:10:00</itunes:duration>
    </item>
    <item>
      <title>Older long episode</title>
      <pubDate>Sun, 5 Jul 2026 12:00:00 +0000</pubDate>
      <enclosure url="https://example.com/older.mp3" type="audio/mpeg" />
      <itunes:duration>130:00</itunes:duration>
    </item>
    <item>
      <title>No duration</title>
      <pubDate>Mon, 6 Jul 2026 13:00:00 +0000</pubDate>
      <enclosure url="https://example.com/noduration.mp3" type="audio/mpeg" />
    </item>
  </channel>
</rss>
""".encode("utf-8")


LATEST_MISSING_ENCLOSURE_RSS = """<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  <channel>
    <item>
      <title>Broken latest long episode</title>
      <pubDate>Mon, 6 Jul 2026 12:00:00 +0000</pubDate>
      <itunes:duration>02:10:00</itunes:duration>
    </item>
  </channel>
</rss>
""".encode("utf-8")


NO_ELIGIBLE_EPISODE_RSS = """<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  <channel>
    <item>
      <title>Only short episode</title>
      <pubDate>Mon, 6 Jul 2026 12:00:00 +0000</pubDate>
      <enclosure url="https://example.com/short.mp3" type="audio/mpeg" />
      <itunes:duration>02:00:00</itunes:duration>
    </item>
  </channel>
</rss>
""".encode("utf-8")


class ParseDurationTests(unittest.TestCase):
    def test_accepts_seconds_only(self) -> None:
        self.assertEqual(parse_duration("59"), 59)

    def test_accepts_minutes_and_seconds(self) -> None:
        self.assertEqual(parse_duration("130:00"), 7800)

    def test_accepts_hours_minutes_seconds(self) -> None:
        self.assertEqual(parse_duration("02:00:01"), 7201)

    def test_rejects_empty_value(self) -> None:
        with self.assertRaises(ValueError):
            parse_duration("   ")


class SanitizeFilenameTests(unittest.TestCase):
    def test_removes_invalid_windows_characters_and_accents(self) -> None:
        title = "\u00c9pisode: Jo\u00eblle / test?"
        self.assertEqual(sanitize_filename(title), "Episode_Joelle_test.mp3")

    def test_avoids_reserved_windows_name(self) -> None:
        self.assertEqual(sanitize_filename("CON"), "episode_CON.mp3")


class FindLatestEpisodeTests(unittest.TestCase):
    def test_picks_latest_episode_over_2h(self) -> None:
        episode = find_latest_episode_over_2h(SAMPLE_RSS)
        self.assertEqual(episode.title, "Latest long episode")
        self.assertEqual(episode.duration_seconds, 7800)
        self.assertEqual(episode.mp3_url, "https://example.com/latest.mp3")

    def test_rejects_latest_episode_without_enclosure(self) -> None:
        with self.assertRaises(PodcastFetchError):
            find_latest_episode_over_2h(LATEST_MISSING_ENCLOSURE_RSS)

    def test_raises_when_no_episode_is_long_enough(self) -> None:
        with self.assertRaises(PodcastFetchError):
            find_latest_episode_over_2h(NO_ELIGIBLE_EPISODE_RSS)


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