#!/usr/bin/python3
"""Test confirming paraminfo contains expected values."""
#
# (C) Pywikibot team, 2015-2022
#
# Distributed under the terms of the MIT license.
#
from pywikibot.family import WikimediaFamily
from pywikibot.page import Claim, Property
from pywikibot.site import DataSite
from tests.aspects import (
    DefaultSiteTestCase,
    DefaultWikibaseClientTestCase,
    TestCaseBase,
    WikimediaDefaultSiteTestCase,
    unittest,
)
from tests.utils import skipping


class KnownTypesTestBase(TestCaseBase):

    """Base class for paraminfo checks."""

    def _get_param_values(self, site, module, parameter):
        """Perform check that a parameter matches the expected list."""
        with skipping(
            ValueError,
                msg='Paraminfo for {} could not be loaded'.format(module)):
            param = site._paraminfo.parameter(module, parameter)

        if not param or 'type' not in param:
            raise unittest.SkipTest(
                'No defined values for {}.{}'.format(module, parameter))
        return param['type']

    def _check_param_values(self, site, module, parameter, expected):
        """Check that a parameter matches the expected list exactly."""
        values = self._get_param_values(site, module, parameter)
        self.assertCountEqual(expected, values)

    def _check_param_subset(self, site, module, parameter, expected):
        """Check that a parameter contains all entries in expected list."""
        values = self._get_param_values(site, module, parameter)
        self.assertLessEqual(set(expected), set(values))

    def _check_param_superset(self, site, module, parameter, expected):
        """Check that a parameter only contains entries in expected list."""
        values = self._get_param_values(site, module, parameter)
        exp = set(expected)
        val = set(values)
        if not exp.issuperset(val):
            diff = val - exp
            self.fail('Unexpected param{} {} in values'
                      .format('s' if len(diff) > 1 else '', diff))


class MediaWikiKnownTypesTestCase(KnownTypesTestBase,
                                  DefaultSiteTestCase):

    """Verify MediaWiki types using paraminfo."""

    def test_api_format(self):
        """Test api format."""
        known = ['json', 'xml']
        self._check_param_subset(self.site, 'main', 'format', known)

    def test_assert_user(self):
        """Test assert type."""
        known = ['user', 'bot']
        self._check_param_subset(self.site, 'main', 'assert', known)

    def test_feed_format(self):
        """Test feed format."""
        known = ['rss', 'atom']

        if self.site.has_extension('GoogleNewsSitemap'):
            known.append('sitemap')

        self._check_param_values(
            self.site, 'feedwatchlist', 'feedformat', known)

    def test_watchlist_show_flags(self):
        """Test watchlist show flags."""
        types = ['minor', 'bot', 'anon', 'patrolled']
        if self.site.mw_version >= '1.24':
            types.append('unread')

        known = types + ['!{}'.format(item) for item in types]

        self._check_param_subset(self.site, 'query+watchlist', 'show', known)

    def test_watchlist_type(self):
        """Test watchlist type."""
        known = ['edit', 'external', 'new', 'log']

        mw_ver = self.site.mw_version

        if mw_ver.version >= (1, 27) \
           and (mw_ver >= '1.27.0-wmf.4' or mw_ver.suffix == 'alpha'):
            known.append('categorize')

        self._check_param_values(self.site, 'query+watchlist', 'type', known)

    def test_watchlist_modification_flag(self):
        """Test watchlist modification flag."""
        known = ['watch', 'unwatch', 'preferences', 'nochange']

        self._check_param_values(self.site, 'edit', 'watchlist', known)
        self._check_param_values(self.site, 'delete', 'watchlist', known)
        self._check_param_values(self.site, 'move', 'watchlist', known)
        self._check_param_values(self.site, 'protect', 'watchlist', known)
        self._check_param_values(self.site, 'rollback', 'watchlist', known)
        self._check_param_values(self.site, 'undelete', 'watchlist', known)

        known = ['watch', 'preferences', 'nochange']
        self._check_param_values(self.site, 'upload', 'watchlist', known)

    def test_content_format(self):