import os
from kabaret import flow
from kabaret.flow_contextual_dict import get_contextual_dict
from libreflow.utils.flow.import_files import ImportFilesAction as BaseImportFilesAction
from libreflow.flows.default.flow import Project
from libreflow.baseflow.film import FilmCollection
from libreflow.baseflow.task import (
    CreateDefaultTasksAction,
    DefaultTaskView as BaseDefaultTaskView,
    DefaultTaskViewItem as BaseDefaultTaskViewItem,
)
from libreflow.flows.default.flow.shot import (
    Shot as BaseShot,
    Shots as BaseShots,
    Sequence
)

from . import _version
__version__ = _version.get_versions()['version']


class ImportFilesAction(BaseImportFilesAction):

    def resolve_paths(self, paths):
        for path in paths:
            # Find matching file
            file_name = os.path.basename(path)
            match_file, task_names = self.resolve_file(file_name)

            # If the action was started from a task,
            # there is no need to resolve entities
            target_oid = None
            match_dict = None
            if self.source_task.get():
                target_oid = self.source_task.get()
            else:
                match_dict = self.resolve_entities(file_name, match_file)

            # Create item
            index = len(self.settings.files_map.mapped_items())
            item = self.settings.files_map.add(f'file{index+1}')

            # Set values
            item.file_path.set(path)
            item.file_name.set(file_name)
            item.file_match_name.set(match_file)
            item.file_extension.set(os.path.splitext(file_name)[1] if os.path.isfile(path) else None)

            item.film_name.set(
                match_dict['film'] if match_dict
                else self.get_entity_from_oid(target_oid, 'films')
            )
            item.sequence_name.set(
                match_dict['sequence'] if match_dict
                else self.get_entity_from_oid(target_oid, 'sequences')
            )
            if item.sequence_name.get() is not None and "sq" not in item.sequence_name.get():
                item.sequence_name.set(f"sq{item.sequence_name.get()}")
            item.shot_name.set(
                match_dict['shot'] if match_dict
                else self.get_entity_from_oid(target_oid, 'shots')
            )
            if item.shot_name.get() is not None and "sh" not in item.shot_name.get():
                item.shot_name.set(f"sh{item.shot_name.get()}")
            item.asset_lib_name.set(
                match_dict.get('asset_lib', None) if match_dict
                else self.get_entity_from_oid(target_oid, 'asset_libs')
            )
            item.asset_type_name.set(
                match_dict['asset_type'] if match_dict
                else self.get_entity_from_oid(target_oid, 'asset_types')
            )
            item.asset_family_name.set(
                match_dict['asset_family'] if match_dict
                else self.get_entity_from_oid(target_oid, 'asset_families')
            )
            item.asset_name.set(
                match_dict['asset'] if match_dict
                else self.get_entity_from_oid(target_oid, 'assets')
            )
            item.task_name.set(
                self.get_entity_from_oid(target_oid, 'tasks') if target_oid
                else task_names
            )
            item.file_target_oid.set(target_oid if target_oid else self.set_target_oid(item))

            # Define status
            
            # Valid if we know the matching file,
            # have all shot or asset data,
            # and one target task possible

            status = True
            shot_attr = [
                item.film_name.get(),
                item.sequence_name.get(),
                item.shot_name.get()
            ]
            asset_attr = [
                item.asset_type_name.get(),
                item.asset_name.get()
            ]
            if self.get_project_type() == 'tvshow':
                asset_attr.append(item.asset_lib_name.get())
            
            if (
                match_file is None

                or any([
                    all(value is not None for value in shot_attr),
                    all(value is not None for value in asset_attr)
                ]) is False

                or (
                    type(item.task_name.get()) is list
                    and len(item.task_name.get()) > 1
                )
            ):
                status = False

            item.file_status.set(status)


class DefaultTaskViewItem(BaseDefaultTaskViewItem):

    def refresh(self):
        super(DefaultTaskViewItem, self).refresh()
        kitsu_status = self._map.kitsu_api.get_shot_task_status_name(
            self._map.context_dict['sequence'],
            self._map.context_dict['shot'],
            self.default.kitsu_tasks.get()[0]
        )
        if kitsu_status.lower() == "out":
            self.enabled.set(False)


class DefaultTaskView(BaseDefaultTaskView):

    def __init__(self, parent, name):
        super(DefaultTaskView, self).__init__(parent, name)
        self.kitsu_api = self.root().project().kitsu_api()
        self.context_dict = get_contextual_dict(self._entity, "settings")

    @classmethod
    def mapped_type(cls):
        return flow.injection.injectable(DefaultTaskViewItem)


class Shot(BaseShot):

    def ensure_tasks(self):
        """
        Creates the tasks of this shot based on the task
        templates of the project, skipping any existing task.
        """
        mgr = self.root().project().get_task_manager()

        kitsu_api = self.root().project().kitsu_api()
        context_dict = get_contextual_dict(self, "settings")

        for dt in mgr.get_default_tasks(template_name='shot', exclude_optional=True, entity_oid=self.oid()):
            if not self.tasks.has_mapped_name(dt.name()):
                kitsu_status = kitsu_api.get_shot_task_status_name(
                    context_dict['sequence'],
                    context_dict['shot'],
                    dt.kitsu_tasks.get()[0]
                )
                if kitsu_status.lower() == "out":
                    continue

                t = self.tasks.add(dt.name())
                t.enabled.set(dt.enabled.get())

        self.tasks.touch()


class Shots(BaseShots):

    @classmethod
    def mapped_type(cls):
        return flow.injection.injectable(Shot)


def import_files(parent):
    # Hide original action
    if isinstance(parent, Project):
        r = flow.Child(flow.Object)
        r.ui(hidden=True)
        r.name = 'import_files'
        return r
    # Recreate action in a sub object
    if isinstance(parent, FilmCollection):
        r = flow.Child(ImportFilesAction).ui(dialog_size=(800,600))
        r.name = 'import_files'
        r.index = 1
        return r

def kitsu_tasks(parent):
    if isinstance(parent, CreateDefaultTasksAction):
        r = flow.Child(DefaultTaskView).ui(expanded=True)
        r.name = 'default_tasks'
        r.index = 1
        return r
    if isinstance(parent, Sequence):
        r = flow.Child(Shots).ui(
            expanded=True, 
            show_filter=True,
            default_height=600
        )
        r.name = 'shots'
        r.index = 3
        return r


def install_extensions(session):
    return {
        "nebuleuse": [
            import_files,
            kitsu_tasks
        ]
    }
