import os
from pype.modules.ftrack.lib import BaseAction, statics_icon
from avalon import lib as avalonlib
from pype.api import (
    Anatomy,
    get_project_settings
)
from pype.lib import ApplicationManager


class CreateFolders(BaseAction):
    identifier = "create.folders"
    label = "Create Folders"
    icon = statics_icon("ftrack", "action_icons", "CreateFolders.svg")

    def discover(self, session, entities, event):
        if len(entities) != 1:
            return False

        not_allowed = ["assetversion", "project"]
        if entities[0].entity_type.lower() in not_allowed:
            return False

        return True

    def interface(self, session, entities, event):
        if event["data"].get("values", {}):
            return
        entity = entities[0]
        without_interface = True
        for child in entity["children"]:
            if child["object_type"]["name"].lower() != "task":
                without_interface = False
                break
        self.without_interface = without_interface
        if without_interface:
            return
        title = "Create folders"

        entity_name = entity["name"]
        msg = (
            "<h2>Do you want create folders also"
            " for all children of \"{}\"?</h2>"
        )
        if entity.entity_type.lower() == "project":
            entity_name = entity["full_name"]
            msg = msg.replace(" also", "")
            msg += "<h3>(Project root won't be created if not checked)</h3>"
        items = []
        item_msg = {
            "type": "label",
            "value": msg.format(entity_name)
        }
        item_label = {
            "type": "label",
            "value": "With all chilren entities"
        }
        item = {
            "name": "children_included",
            "type": "boolean",
            "value": False
        }
        items.append(item_msg)
        items.append(item_label)
        items.append(item)

        return {
            "items": items,
            "title": title
        }

    def launch(self, session, entities, event):
        '''Callback method for custom action.'''
        with_childrens = True
        if self.without_interface is False:
            if "values" not in event["data"]:
                return
            with_childrens = event["data"]["values"]["children_included"]

        entity = entities[0]
        if entity.entity_type.lower() == "project":
            proj = entity
        else:
            proj = entity["project"]
        project_name = proj["full_name"]
        project_code = proj["name"]

        if entity.entity_type.lower() == 'project' and with_childrens is False:
            return {
                'success': True,
                'message': 'Nothing was created'
            }

        all_entities = []
        all_entities.append(entity)
        if with_childrens:
            all_entities = self.get_notask_children(entity)

        anatomy = Anatomy(project_name)
        project_settings = get_project_settings(project_name)

        work_keys = ["work", "folder"]
        work_template = anatomy.templates
        for key in work_keys:
            work_template = work_template[key]
        work_has_apps = "{app" in work_template

        publish_keys = ["publish", "folder"]
        publish_template = anatomy.templates
        for key in publish_keys:
            publish_template = publish_template[key]
        publish_has_apps = "{app" in publish_template

        tools_settings = project_settings["global"]["tools"]
        app_presets = tools_settings["Workfiles"]["sw_folders"]
        app_manager_apps = None
        if app_presets and (work_has_apps or publish_has_apps):
            app_manager_apps = ApplicationManager().applications

        cached_apps = {}
        collected_paths = []
        for entity in all_entities:
            if entity.entity_type.lower() == "project":
                continue
            ent_data = {
                "project": {
                    "name": project_name,
                    "code": project_code
                }
            }

            ent_data["asset"] = entity["name"]

            parents = entity["link"][1:-1]
            hierarchy_names = [p["name"] for p in parents]
            hierarchy = ""
            if hierarchy_names:
                hierarchy = os.path.sep.join(hierarchy_names)
            ent_data["hierarchy"] = hierarchy

            tasks_created = False
            for child in entity["children"]:
                if child["object_type"]["name"].lower() != "task":
                    continue
                tasks_created = True
                task_type_name = child["type"]["name"].lower()
                task_data = ent_data.copy()
                task_data["task"] = child["name"]

                apps = []
                if app_manager_apps:
                    possible_apps = app_presets.get(task_type_name) or []
                    for app_name in possible_apps:

                        if app_name in cached_apps:
                            apps.append(cached_apps[app_name])
                            continue

                        app_def = app_manager_apps.get(app_name)
                        if app_def and app_def.is_host:
                            app_dir = app_def.host_name
                        else:
                            app_dir = app_name
                        cached_apps[app_name] = app_dir
                        apps.append(app_dir)

                # Template wok
                if work_has_apps:
                    app_data = task_data.copy()
                    for app in apps:
                        app_data["app"] = app
                        collected_paths.append(self.compute_template(
                            anatomy, app_data, work_keys
                        ))
                else:
                    collected_paths.append(self.compute_template(
                        anatomy, task_data, work_keys
                    ))

                # Template publish
                if publish_has_apps:
                    app_data = task_data.copy()
                    for app in apps:
                        app_data["app"] = app
                        collected_paths.append(self.compute_template(
                            anatomy, app_data, publish_keys
                        ))
                else:
                    collected_paths.append(self.compute_template(
                        anatomy, task_data, publish_keys
                    ))

            if not tasks_created:
                # create path for entity
                collected_paths.append(self.compute_template(
                    anatomy, ent_data, work_keys
                ))
                collected_paths.append(self.compute_template(
                    anatomy, ent_data, publish_keys
                ))

        if len(collected_paths) == 0:
            return {
                "success": True,
                "message": "No project folders to create."
            }

        self.log.info("Creating folders:")

        for path in set(collected_paths):
            self.log.info(path)
            if not os.path.exists(path):
                os.makedirs(path)

        return {
            "success": True,
            "message": "Successfully created project folders."
        }

    def get_notask_children(self, entity):
        output = []
        if entity.entity_type.lower() == "task":
            return output

        output.append(entity)
        for child in entity["children"]:
            output.extend(self.get_notask_children(child))
        return output

    def compute_template(self, anatomy, data, anatomy_keys):
        filled_template = anatomy.format_all(data)
        for key in anatomy_keys:
            filled_template = filled_template[key]

        if filled_template.solved:
            return os.path.normpath(filled_template)

        self.log.warning(
            "Template \"{}\" was not fully filled \"{}\"".format(
                filled_template.template, filled_template
            )
        )
        return os.path.normpath(filled_template.split("{")[0])


def register(session):
    """Register plugin. Called when used as an plugin."""
    CreateFolders(session).register()
