# mkdocs-changelog-feed-plugin
# Copyright (C) 2025 Tobias Bölz
#
# This program is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.
from pathlib import Path
from xml.etree.ElementTree import ElementTree

import pytest
from bs4 import BeautifulSoup
from click.testing import CliRunner
from mkdocs.__main__ import cli
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.exceptions import PluginError

from mkdocs_changelog_feed_plugin.changelog_feed import ChangelogFeedPlugin


@pytest.fixture(scope='module')
def site_dir(request, tmp_path_factory) -> Path:
    try:
        config_file_name = request.param
    except AttributeError:
        config_file_name = 'mkdocs.yaml'

    config_file = Path(__file__).parent / config_file_name
    site_dir = tmp_path_factory.mktemp('site')
    runner = CliRunner()
    result = runner.invoke(
        cli, ['build', '--site-dir', str(site_dir), '--config-file', str(config_file)]
    )
    assert result.exit_code == 0
    return site_dir


def test_atom_feed(site_dir: Path):
    atom_feed = ElementTree(file=site_dir / 'CHANGELOG.atom.xml')
    namespaces = {'atom': 'http://www.w3.org/2005/Atom'}
    assert (
        atom_feed.find('./atom:author/atom:name', namespaces).text == 'J. Random Hacker'
    )
    assert atom_feed.find('./atom:entry/atom:title', namespaces).text == 'Unreleased'
    assert atom_feed.find('./atom:entry[2]/atom:title', namespaces).text == '1.0.1'
    assert (
        atom_feed.find('./atom:entry[2]/atom:published', namespaces).text
        == '2023-03-05T12:00:00+00:00'
    )


def test_rss_feed(site_dir: Path):
    rss_feed = ElementTree(file=site_dir / 'CHANGELOG.rss.xml')
    assert rss_feed.find('./channel/item/title').text == 'Unreleased'
    assert (
        rss_feed.find(
            './channel/item/dc:creator', {'dc': 'http://purl.org/dc/elements/1.1/'}
        ).text
        == 'J. Random Hacker'
    )
    assert rss_feed.find('./channel/item[2]/title').text == '1.0.1'
    assert (
        rss_feed.find('./channel/item[2]/pubDate').text
        == 'Sun, 05 Mar 2023 12:00:00 +0000'
    )


def test_link_tags_in_head(site_dir: Path):
    changelog_output = site_dir / 'CHANGELOG' / 'index.html'
    soup = BeautifulSoup(changelog_output.read_text(), 'html.parser')
    assert soup.find(
        'link',
        rel='alternate',
        href='../CHANGELOG.atom.xml',
        type='application/atom+xml',
    )
    assert soup.find(
        'link', rel='alternate', href='../CHANGELOG.rss.xml', type='application/rss+xml'
    )


def test_links_in_body(site_dir: Path):
    changelog_output = site_dir / 'CHANGELOG' / 'index.html'
    soup = BeautifulSoup(changelog_output.read_text(), 'html.parser')
    assert soup.find('a', string='Atom feed', href='../CHANGELOG.atom.xml')
    assert soup.find('a', string='RSS feed', href='../CHANGELOG.rss.xml')


def test_no_trailing_slashes(site_dir: Path):
    changelog_output = site_dir / 'CHANGELOG' / 'index.html'
    assert '/>' not in changelog_output.read_text()


@pytest.mark.parametrize(
    'site_dir, should_remove_permalinks',
    [
        ('mkdocs.yaml', True),
        ('mkdocs-remove-permalinks-false.yaml', False),
    ],
    indirect=['site_dir'],
)
def test_remove_permalinks(site_dir: Path, should_remove_permalinks: bool):
    rss_feed = ElementTree(file=site_dir / 'CHANGELOG.rss.xml')
    soup = BeautifulSoup(
        rss_feed.find('./channel/item/description').text, 'html.parser'
    )
    permalink_exists = soup.find('a', attrs={'class': 'headerlink'}) is not None
    assert permalink_exists is not should_remove_permalinks


def test_no_site_url():
    config = MkDocsConfig()
    config.site_url = None
    plugin = ChangelogFeedPlugin()

    with pytest.raises(PluginError):
        plugin.on_config(config)


def test_no_site_author(capsys):
    config = MkDocsConfig()
    config.site_url = 'https://example.com'
    config.site_author = None
    plugin = ChangelogFeedPlugin()

    plugin.on_config(config)

    captured = capsys.readouterr()
    assert 'mkdocs_changelog_feed_plugin' in captured.err
    assert (
        'The site_author setting is required to create a valid Atom feed.'
        in captured.err
    )
