#!/usr/bin/env python

import os
import tempfile
import unittest
from tempfile import TemporaryDirectory

import mkdocs
from mkdocs import config
from mkdocs.config import config_options
from mkdocs.config import defaults
from mkdocs.exceptions import ConfigurationError
from mkdocs.localization import parse_locale
from mkdocs.tests.base import dedent


class ConfigTests(unittest.TestCase):
    def test_missing_config_file(self):
        with self.assertRaises(ConfigurationError):
            config.load_config(config_file='bad_filename.yaml')

    def test_missing_site_name(self):
        c = config.Config(schema=defaults.get_schema())
        c.load_dict({})
        errors, warnings = c.validate()
        self.assertEqual(len(errors), 1)
        self.assertEqual(errors[0][0], 'site_name')
        self.assertEqual(str(errors[0][1]), 'Required configuration not provided.')

        self.assertEqual(len(warnings), 0)

    def test_empty_config(self):
        with self.assertRaises(ConfigurationError):
            config.load_config(config_file='/dev/null')

    def test_nonexistant_config(self):
        with self.assertRaises(ConfigurationError):
            config.load_config(config_file='/path/that/is/not/real')

    def test_invalid_config(self):
        file_contents = dedent("""
        - ['index.md', 'Introduction']
        - ['index.md', 'Introduction']
        - ['index.md', 'Introduction']
        """)
        config_file = tempfile.NamedTemporaryFile('w', delete=False)
        try:
            config_file.write(file_contents)
            config_file.flush()
            config_file.close()

            with self.assertRaises(ConfigurationError):
                config.load_config(config_file=open(config_file.name, 'rb'))
        finally:
            os.remove(config_file.name)

    def test_config_option(self):
        """
        Users can explicitly set the config file using the '--config' option.
        Allows users to specify a config other than the default `mkdocs.yml`.
        """
        expected_result = {
            'site_name': 'Example',
            'nav': [
                {'Introduction': 'index.md'}
            ],
        }
        file_contents = dedent("""
        site_name: Example
        nav:
        - 'Introduction': 'index.md'
        """)
        with TemporaryDirectory() as temp_path:
            os.mkdir(os.path.join(temp_path, 'docs'))
            config_path = os.path.join(temp_path, 'mkdocs.yml')
            config_file = open(config_path, 'w')

            config_file.write(file_contents)
            config_file.flush()
            config_file.close()

            result = config.load_config(config_file=config_file.name)
            self.assertEqual(result['site_name'], expected_result['site_name'])
            self.assertEqual(result['nav'], expected_result['nav'])

    def test_theme(self):
        with TemporaryDirectory() as mytheme, TemporaryDirectory() as custom:
            configs = [
                dict(),  # default theme
                {"theme": "readthedocs"},  # builtin theme
                {"theme": {'name': 'readthedocs'}},  # builtin as complex
                {"theme": {'name': None, 'custom_dir': mytheme}},  # custom only as complex
                {"theme": {'name': 'readthedocs', 'custom_dir': custom}},  # builtin and custom as complex
                {  # user defined variables
                    'theme': {
                        'name': 'mkdocs',
                        'locale': 'fr',
                        'static_templates': ['foo.html'],
                        'show_sidebar': False,
                        'some_var': 'bar'
                    }
                }
            ]

            mkdocs_dir = os.path.abspath(os.path.dirname(mkdocs.__file__))
            mkdocs_templates_dir = os.path.join(mkdocs_dir, 'templates')
            theme_dir = os.path.abspath(os.path.join(mkdocs_dir, 'themes'))

            results = (
                {
                    'dirs': [os.path.join(theme_dir, 'mkdocs'), mkdocs_templates_dir],
                    'static_templates': ['404.html', 'sitemap.xml'],
                    'vars': {
                        'locale': parse_locale('en'),
                        'include_search_page': False,
                        'search_index_only': False,
                        'analytics': {'gtag': None},
                        'highlightjs': True,
                        'hljs_style': 'github',
                        'hljs_languages': [],
                        'navigation_depth': 2,
                        'nav_style': 'primary',
                        'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83}
                    }
                }, {
                    'dirs': [os.path.join(theme_dir, 'readthedocs'), mkdocs_templates_dir],
                    'static_templates': ['404.html', 'sitemap.xml'],
                    'vars': {
                        'locale': parse_locale('en'),
                        'include_search_page': True,
                        'search_index_only': False,
                        'analytics': {'anonymize_ip': False, 'gtag': None},
                        'highlightjs': True,
                        'hljs_languages': [],
                        'include_homepage_in_sidebar': True,
                        'prev_next_buttons_location': 'bottom',
                        'navigation_depth': 4,
                        'sticky_navigation': True,
                        'logo': None,
                        'titles_only': False,
                        'collapse_navigation': True
                    }
                }, {
                    'dirs': [os.path.join(theme_dir, 'readthedocs'), mkdocs_templates_dir],
                    'static_templates': ['404.html', 'sitemap.xml'],
                    'vars': {
                        'locale': parse_locale('en'),
                        'include_search_page': True,
                        'search_index_only': False,
                        'analytics': {'anonymize_ip': False, 'gtag': None},
                        'highlightjs': True,
                        'hljs_languages': [],
                        'include_homepage_in_sidebar': True,
                        'prev_next_buttons_location': 'bottom',
                        'navigation_depth': 4,
                        'sticky_navigation': True,
                        'logo': None,
                        'titles_only': False,
                        'collapse_navigation': True
                    }
                }, {
                    'dirs': [mytheme, mkdocs_templates_dir],
                    'static_templates': ['sitemap.xml'],
                    'vars': {'locale': parse_locale('en')}
                }, {
                    'dirs': [custom, os.path.join(theme_dir, 'readthedocs'), mkdocs_templates_dir],
                    'static_templates': ['404.html', 'sitemap.xml'],
                    'vars': {
                        'locale': parse_locale('en'),
                        'include_search_page': True,
                        'search_index_only': False,
                        'analytics': {'anonymize_ip': False, 'gtag': None},
                        'highlightjs': True,
                        'hljs_languages': [],
                        'include_homepage_in_sidebar': True,
                        'prev_next_buttons_location': 'bottom',
                        'navigation_depth': 4,
                        'sticky_navigation': True,
                        'logo': None,
                        'titles_only': False,
                        'collapse_navigation': True
                    }
                }, {
                    'dirs': [os.path.join(theme_dir, 'mkdocs'), mkdocs_templates_dir],
                    'static_templates': ['404.html', 'sitemap.xml', 'foo.html'],
                    'vars': {
                        'locale': parse_locale('fr'),
                        'show_sidebar': False,
                        'some_var': 'bar',
                        'include_search_page': False,
                        'search_index_only': False,
                        'analytics': {'gtag': None},
                        'highlightjs': True,
                        'hljs_style': 'github',
                        'hljs_languages': [],
                        'navigation_depth': 2,
                        'nav_style': 'primary',
                        'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83}
                    }
                }
            )

            for config_contents, result in zip(configs, results):

                c = config.Config(schema=(('theme', config_options.Theme(default='mkdocs')),))
                c.load_dict(config_contents)
                errors, warnings = c.validate()
                self.assertEqual(len(errors), 0)
                self.assertEqual(c['theme'].dirs, result['dirs'])
                self.assertEqual(c['theme'].static_templates, set(result['static_templates']))
                self.assertEqual({k: c['theme'][k] for k in iter(c['theme'])}, result['vars'])

    def test_empty_nav(self):
        conf = config.Config(schema=defaults.get_schema())
        conf.load_dict({
            'site_name': 'Example',
            'config_file_path': os.path.join(os.path.abspath('.'), 'mkdocs.yml')
        })
        conf.validate()
        self.assertEqual(conf['nav'], None)

    def test_error_on_pages(self):
        conf = config.Config(schema=defaults.get_schema())
        conf.load_dict({
            'site_name': 'Example',
            'pages': ['index.md', 'about.md'],
        })
        errors, warnings = conf.validate()
        self.assertEqual(warnings, [])
        self.assertEqual(len(errors), 1)
        self.assertEqual(
            str(errors[0][1]),
            "The configuration option 'pages' was removed from MkDocs. Use 'nav' instead."
        )

    def test_doc_dir_in_site_dir(self):

        j = os.path.join

        test_configs = (
            {'docs_dir': j('site', 'docs'), 'site_dir': 'site'},
            {'docs_dir': 'docs', 'site_dir': '.'},
            {'docs_dir': '.', 'site_dir': '.'},
            {'docs_dir': 'docs', 'site_dir': ''},
            {'docs_dir': '', 'site_dir': ''},
            {'docs_dir': 'docs', 'site_dir': 'docs'},
        )

        conf = {
            'config_file_path': j(os.path.abspath('..'), 'mkdocs.yml')
        }

        for test_config in test_configs:

            patch = conf.copy()
            patch.update(test_config)

            # Same as the default schema, but don't verify the docs_dir exists.
            c = config.Config(schema=(
                ('docs_dir', config_options.Dir(default='docs')),
                ('site_dir', config_options.SiteDir(default='site')),
                ('config_file_path', config_options.Type(str))
            ))
            c.load_dict(patch)

            errors, warnings = c.validate()

            self.assertEqual(len(errors), 1)
            self.assertEqual(warnings, [])

    def testConfigInstancesUnique(self):
        conf = mkdocs.config.Config(mkdocs.config.defaults.get_schema())
        conf.load_dict({'site_name': 'foo'})
        conf.validate()
        self.assertIsNone(conf['mdx_configs'].get('toc'))

        conf = mkdocs.config.Config(mkdocs.config.defaults.get_schema())
        conf.load_dict({'site_name': 'foo', 'markdown_extensions': [{"toc": {"permalink": "aaa"}}]})
        conf.validate()
        self.assertEqual(conf['mdx_configs'].get('toc'), {'permalink': 'aaa'})

        conf = mkdocs.config.Config(mkdocs.config.defaults.get_schema())
        conf.load_dict({'site_name': 'foo'})
        conf.validate()
        self.assertIsNone(conf['mdx_configs'].get('toc'))
