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

from pathlib import Path
from unittest.mock import patch

from sun.fetcher import Fetcher
from sun.utils import Utilities


MIRROR_LOG = (
    'Mon Feb 03 2025 00:00:00 UTC\n'
    'patches/packages/vim-9.0-x86_64-1.txz:  Upgraded.\n'
    'Mon Feb 01 2025 00:00:00 UTC\n'
    'patches/packages/curl-7.85-x86_64-1.txz:  Rebuilt.\n'
)
LOCAL_LOG = 'Mon Feb 01 2025 00:00:00 UTC\nsome package line\n'


class TestFetcherUpdates:

    def test_yields_packages_newer_than_local_date(self):
        fetcher = Fetcher()
        with patch.object(Utilities, 'fetch_if_modified', return_value=(MIRROR_LOG, 'Mon, 03 Feb 2025 00:00:00 GMT')):
            with patch.object(Utilities, 'read_local_text_file', return_value=LOCAL_LOG):
                packages = list(fetcher.updates())
        assert any('vim' in p for p in packages)
        assert not any('curl' in p for p in packages)

    def test_stops_at_local_date(self):
        fetcher = Fetcher()
        mirror = 'Mon Feb 01 2025 00:00:00 UTC\npatches/packages/vim-9.0-x86_64-1.txz:  Upgraded.\n'
        with patch.object(Utilities, 'fetch_if_modified', return_value=(mirror, None)):
            with patch.object(Utilities, 'read_local_text_file', return_value=LOCAL_LOG):
                packages = list(fetcher.updates())
        assert packages == []

    def test_empty_local_log_yields_nothing(self):
        fetcher = Fetcher()
        with patch.object(Utilities, 'fetch_if_modified', return_value=(MIRROR_LOG, None)):
            with patch.object(Utilities, 'read_local_text_file', return_value=''):
                packages = list(fetcher.updates())
        assert packages == []

    def test_network_failure_yields_nothing(self):
        fetcher = Fetcher()
        with patch.object(Utilities, 'fetch_if_modified', return_value=(None, None)):
            with patch.object(Utilities, 'read_local_text_file', return_value=LOCAL_LOG):
                packages = list(fetcher.updates())
        assert packages == []

    def test_304_uses_cached_mirror(self):
        fetcher = Fetcher()
        fetcher._mirror_log_cache = MIRROR_LOG
        fetcher._last_modified = 'Mon, 03 Feb 2025 00:00:00 GMT'
        # 304: fetch_if_modified returns (None, existing_lm)
        with patch.object(Utilities, 'fetch_if_modified', return_value=(None, fetcher._last_modified)):
            with patch.object(Utilities, 'read_local_text_file', return_value=LOCAL_LOG):
                packages = list(fetcher.updates())
        assert any('vim' in p for p in packages)

    def test_network_failure_sets_fetch_error(self):
        fetcher = Fetcher()
        with patch.object(Utilities, 'fetch_if_modified', return_value=(None, None)):
            fetcher._fetch_mirror_if_modified()
        assert fetcher.last_fetch_error is True

    def test_cache_hit_clears_fetch_error(self):
        fetcher = Fetcher()
        fetcher.last_fetch_error = True
        fetcher._mirror_log_cache = 'old content'
        with patch.object(Utilities, 'fetch_if_modified', return_value=(None, 'lm')):
            fetcher._fetch_mirror_if_modified()
        assert fetcher.last_fetch_error is False

    def test_no_repo_mirror_yields_nothing(self):
        fetcher = Fetcher()
        with patch.object(fetcher.configs, 'repo_mirror', ''):
            packages = list(fetcher.updates())
        assert packages == []


class TestFetcherFetchMirrorIfModified:

    def test_updates_cache_on_new_content(self):
        fetcher = Fetcher()
        with patch.object(Utilities, 'fetch_if_modified', return_value=('new content', 'some-lm')):
            fetcher._fetch_mirror_if_modified()
        assert fetcher._mirror_log_cache == 'new content'
        assert fetcher._last_modified == 'some-lm'

    def test_keeps_cache_on_304(self):
        fetcher = Fetcher()
        fetcher._mirror_log_cache = 'old content'
        fetcher._last_modified = 'old-lm'
        with patch.object(Utilities, 'fetch_if_modified', return_value=(None, 'old-lm')):
            fetcher._fetch_mirror_if_modified()
        assert fetcher._mirror_log_cache == 'old content'
        assert fetcher._last_modified == 'old-lm'


class TestFetcherExtractDate:

    def test_extracts_first_date_line(self):
        fetcher = Fetcher()
        log = 'Mon Feb 01 2025 00:00:00 UTC\nsome package line\n'
        assert fetcher._extract_date(log) == 'Mon Feb 01 2025 00:00:00 UTC'

    def test_no_date_returns_none(self):
        fetcher = Fetcher()
        assert fetcher._extract_date('some random content\nno date here\n') is None


class TestFetcherPatchLineForSlackware:

    def test_regular_line_unchanged(self):
        line = 'extra/packages/vim-9.0-x86_64-1.txz:  Upgraded.'
        assert Fetcher.patch_line_for_slackware(line) == line

    def test_linux_patch_line(self):
        line = 'patches/packages/linux-5.15.19/linux-5.15.19-x86_64-1.txz:  Upgraded.'
        assert Fetcher.patch_line_for_slackware(line) == 'linux-5.15.19'
