import hashlib
import shutil
from contextlib import suppress
from os import path
from os.path import dirname
from subprocess import check_call
from typing import Optional, List, Tuple, Type, Callable, Iterable, Any

from betty.event import Event
from betty.fs import DirectoryBackup
from betty.generate import PostGenerateEvent
from betty.html import HtmlProvider
from betty.plugin import Plugin, NO_CONFIGURATION
from betty.site import Site


class Trees(Plugin, HtmlProvider):
    def __init__(self, site: Site):
        self._site = site

    @classmethod
    def for_site(cls, site: Site, configuration: Any = NO_CONFIGURATION):
        return cls(site)

    def subscribes_to(self) -> List[Tuple[Type[Event], Callable]]:
        return [
            (PostGenerateEvent, self._render),
        ]

    @property
    def assets_directory_path(self) -> Optional[str]:
        return '%s/assets' % dirname(__file__)

    async def _render(self, event: PostGenerateEvent) -> None:
        build_directory_path = path.join(self._site.configuration.cache_directory_path, self.name(), hashlib.md5(self.assets_directory_path.encode()).hexdigest())

        plugin_build_directory_path = path.join(
            build_directory_path, self.name())
        async with DirectoryBackup(plugin_build_directory_path, 'node_modules'):
            with suppress(FileNotFoundError):
                shutil.rmtree(plugin_build_directory_path)
            shutil.copytree(path.join(self.assets_directory_path, 'js'),
                            plugin_build_directory_path)
        await self._site.renderer.render_tree(plugin_build_directory_path)

        js_plugin_build_directory_path = path.join(
            build_directory_path, self.name())

        # Install third-party dependencies.
        check_call(['npm', 'install', '--production'],
                   cwd=js_plugin_build_directory_path)

        # Run Webpack.
        await self._site.assets.copy2(path.join(self._site.configuration.www_directory_path, 'betty.css'), path.join(
            js_plugin_build_directory_path, 'betty.css'))
        check_call(['npm', 'run', 'webpack'],
                   cwd=js_plugin_build_directory_path)
        shutil.copy2(path.join(build_directory_path, 'output', 'trees.css'), path.join(
            self._site.configuration.www_directory_path, 'trees.css'))
        shutil.copy2(path.join(build_directory_path, 'output', 'trees.js'), path.join(
            self._site.configuration.www_directory_path, 'trees.js'))

    @property
    def css_paths(self) -> Iterable[str]:
        return {
            self._site.static_url_generator.generate('trees.css'),
        }

    @property
    def js_paths(self) -> Iterable[str]:
        return {
            self._site.static_url_generator.generate('trees.js'),
        }
