import json
import os
import re
import shutil
from pathlib import Path

from oarepo_cli.site.site_support import SiteSupport
from oarepo_cli.utils import copy_tree
from oarepo_cli.wizard import WizardStep


class EditorSupportStep(WizardStep):
    def should_run(self):
        return True

    def after_run(self):
        # create package.json
        site_support: SiteSupport = self.root.site_support

        (self.data.project_dir / "package.json").write_text(
            json.dumps(
                {
                    "name": "for-editor-autocompletion",
                    "description": re.sub(
                        r"\n\s*",
                        " ",
                        """
                    This is an autogenerated package to enable editor autocompletion. 
                    It is not supposed to be committed into git and might be removed at any time.
              """,
                    ).strip(),
                    "version": "1.0.0",
                },
                indent=4,
            )
        )

        # create tsconfig.json

        site_support.call_invenio(
            "oarepo",
            "assets",
            "collect",
            f"{site_support.invenio_instance_path}/watch.list.json",
            "--repository-dir",
            str(self.data.project_dir),
            "--assets-dir",
            "./.assets",
        )

        watch_list = json.loads(
            (site_support.invenio_instance_path / "watch.list.json").read_text()
        )

        aliases = {}
        for alias, root_path in watch_list.get("@root_aliases", {}).items():
            if not root_path.startswith("./"):
                root_path = "./" + root_path
            aliases.setdefault(alias, []).append(root_path)

        Path(self.data.project_dir / "jsconfig.json").write_text(
            json.dumps(
                {"baseUrl": ".", "compilerOptions": {"paths": aliases}},
                indent=4,
                ensure_ascii=False,
            )
        )

        # copy or link node_modules
        assets_path: Path = self.data.project_dir / ".assets"
        modules_path: Path = self.data.project_dir / "node_modules"

        try:
            # if is link, unlink it
            if assets_path.is_dir() and not assets_path.is_symlink():
                shutil.rmtree(assets_path)
        except Exception as e:
            print(
                f"Could not remove {assets_path} as a directory, will try to remove it as a link: {e}"
            )

        try:
            assets_path.unlink()
        except Exception as e:
            print(
                f"Could not remove {assets_path} as a file/link, might have been already removed: {e}"
            )

        try:
            modules_path.unlink(missing_ok=True)
        except Exception as e:
            print(
                f"Could not remove {modules_path} as a file/link, might have been already removed: {e}"
            )

        if self.data.running_in_docker:
            copy_tree(site_support.invenio_instance_path / "assets", assets_path)
        else:
            assets_path.symlink_to(site_support.invenio_instance_path / "assets")

        # can not use Pathlib.symlink_to as it does not create a relative symlink
        os.symlink(".assets/node_modules", modules_path)
