# pylint: disable=protected-access

import os
import re
import tempfile
import time

import pytest

from apt_listchanges.ALCSeenDb import DbError, SeenDb
from apt_listchanges.DebianFiles import ChangelogEntry


def test_corrupt_db():
    with pytest.raises(DbError):
        SeenDb('/dev/null')


def test_read_write_db():
    with tempfile.NamedTemporaryFile(prefix='test_read_write_db') as file_obj:
        os.unlink(file_obj.name)
        seen_db = SeenDb(file_obj.name)
        entry = ChangelogEntry('foo (1.0-1) unstable; urgency=low',
                               '/usr/share/doc/foo/changelog.Debian.gz',
                               'foo', 'foo', '1.0-1', 'low')
        entry.add_content('  Here is some content.\n')
        entry.set_trailer(' -- Nice Guy <example@example.com> '
                          'Thu, 01 Jan 1970 00:00:00 -0000\n')
        seen_db.add(entry)
        seen_db.apply_changes()
        seen_db = SeenDb(file_obj.name)
        assert seen_db.seen_here(entry)
        os.unlink(f'{file_obj.name}-old')


def test_no_source():
    seen_db = SeenDb()
    entry = ChangelogEntry('foo (1.0-1) unstable; urgency=low',
                           '/usr/share/doc/foo/changelog.Debian.gz',
                           'foo', 'foo', '1.0-1', 'low')
    entry.add_content('  Here is some content.\n')
    entry.set_trailer(' -- Nice Guy <example@example.com> '
                      'Thu, 01 Jan 1970 00:00:00 -0000\n')
    assert not seen_db.seen_anywhere(entry, exact=False)


def test_dump(capsys):
    seen_db = SeenDb()
    entry = ChangelogEntry('foo (1.0-1) unstable; urgency=low',
                           '/usr/share/doc/foo/changelog.Debian.gz',
                           'foo', 'foo', '1.0-1', 'low')
    entry.add_content('  Here is some content.\n')
    entry.set_trailer(' -- Nice Guy <example@example.com> '
                      'Thu, 01 Jan 1970 00:00:00 -0000\n')
    seen_db.add(entry)
    seen_db.dump()
    captured = capsys.readouterr()
    print("DUMP OUTPUT:")
    print(captured.out)
    assert re.search(r'packages:\n  foo \d+ \(\d+-\d+-\d+\)\n', captured.out)
    assert re.search(r'exact checksums:\n'
                     r'  /usr/share/doc/foo/changelog\.Debian\.gz:\n'
                     r'    \S+ \d+ \(\d+-\d+-\d+\)\n', captured.out)
    assert re.search(r'similar checksums:\n'
                     r'  /usr/share/doc/foo/changelog.Debian.gz:\n'
                     r'    \S+ \d+ \(\d+-\d+-\d+\)\n', captured.out)


def replace_timestamp(d, timestamp):
    for key, value in d.items():
        if isinstance(value, dict):
            replace_timestamp(value, timestamp)
        else:
            d[key] = timestamp


def test_expire_old():
    seen_db = SeenDb()
    seen_db.add_package('foo')
    entry = ChangelogEntry('foo (1.0-1) unstable; urgency=low',
                           '/usr/share/doc/foo/changelog.Debian.gz',
                           'foo', 'foo', '1.0-1', 'low')
    entry.add_content('  Here is some content.\n')
    entry.set_trailer(' -- Nice Guy <example@example.com> '
                      'Thu, 01 Jan 1970 00:00:00 -0000\n')
    seen_db.add(entry)
    # Gotta muck around inside the seen DB for this test, alas.
    old = time.time() - 365 * 4
    replace_timestamp(seen_db._d.similar, old)
    replace_timestamp(seen_db._d.exact, old)
    replace_timestamp(seen_db._d.packages, old)
    assert (seen_db.has_package('foo') and
            seen_db.seen_anywhere(entry) and
            seen_db.seen_anywhere(entry, exact=False))
    seen_db._expire_old()
    assert not (seen_db.has_package('foo') or
                seen_db.seen_anywhere(entry) or
                seen_db.seen_anywhere(entry, exact=False))


def test_initial_save():
    with tempfile.NamedTemporaryFile(prefix='test_initial_save') as f:
        os.unlink(f.name)
        seen_db = SeenDb(f.name)
        seen_db.add_package('foo')
        seen_db.apply_changes()
        os.unlink(f'{f.name}-old')


def test_update_preserves_changes():
    with tempfile.NamedTemporaryFile(prefix='test_update_preserves_changes') \
         as f:
        os.unlink(f.name)
        seen_db = SeenDb(f.name)
        seen_db.add_package('foo')
        seen_db.apply_changes()
        seen_db = SeenDb(f.name)
        seen_db.add_package('bar')
        seen_db.apply_changes()
        os.unlink(f'{f.name}-old')
        seen_db = SeenDb(f.name)
        assert seen_db.has_package('foo')
        assert seen_db.has_package('bar')


def test_save_as():
    with tempfile.NamedTemporaryFile(prefix='test_save_as1') as f1, \
         tempfile.NamedTemporaryFile(prefix='test_save_as2') as f2:
        os.unlink(f1.name)
        os.unlink(f2.name)
        seen_db = SeenDb(f1.name)
        seen_db.add_package('foo')
        seen_db.apply_changes()
        os.unlink(f'{f1.name}-old')
        seen_db.add_package('bar')
        seen_db.save_as(f2.name)

        seen_db = SeenDb(f1.name)
        assert seen_db.has_package('foo')
        assert not seen_db.has_package('bar')

        seen_db = SeenDb(f2.name)
        assert seen_db.has_package('foo')
        assert seen_db.has_package('bar')
