# SPDX-FileCopyrightText: 2009-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later

import bpy
from bpy.types import (
    Panel,
    UIList,
)
from bpy.app.translations import pgettext_iface as iface_

from rna_prop_ui import PropertyPanel


class WorkSpaceButtonsPanel:
    # bl_space_type = 'PROPERTIES'
    # bl_region_type = 'WINDOW'
    # bl_context = ".workspace"

    # Developer note: this is displayed in tool settings as well as the 3D view.
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Tool"


class WORKSPACE_PT_main(WorkSpaceButtonsPanel, Panel):
    bl_label = "Workspace"
    bl_options = {'DEFAULT_CLOSED'}

    def draw(self, context):
        workspace = context.workspace

        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False

        layout.prop(workspace, "use_pin_scene")
        layout.prop(workspace, "object_mode", text="Mode")


class WORKSPACE_PT_addons(WorkSpaceButtonsPanel, Panel):
    bl_label = "Filter Add-ons"
    bl_parent_id = "WORKSPACE_PT_main"
    addon_map = {}
    owner_ids = set()

    def draw_header(self, context):
        workspace = context.workspace
        self.layout.prop(workspace, "use_filter_by_owner", text="")

    def draw(self, context):
        layout = self.layout

        workspace = context.workspace
        prefs = context.preferences

        import addon_utils
        WORKSPACE_PT_addons.addon_map = {mod.__name__: mod for mod in addon_utils.modules()}
        WORKSPACE_PT_addons.owner_ids = {owner_id.name for owner_id in workspace.owner_ids}
        known_addons = set()
        for addon in prefs.addons:
            if addon.module in WORKSPACE_PT_addons.owner_ids:
                known_addons.add(addon.module)
        unknown_addons = WORKSPACE_PT_addons.owner_ids.difference(known_addons)
        layout.template_list(
            "WORKSPACE_UL_addons_items",
            "",
            context.preferences,
            "addons",
            context.workspace,
            "active_addon",
            rows=8,
        )
        # Detect unused
        if unknown_addons:
            layout.label(text="Unknown add-ons", icon='ERROR')
            col = layout.box().column(align=True)
            for addon_module_name in sorted(unknown_addons):
                row = col.row()
                row.alignment = 'LEFT'
                row.operator(
                    "wm.owner_disable",
                    icon='CHECKBOX_HLT',
                    text=addon_module_name,
                    emboss=False,
                ).owner_id = addon_module_name


class WORKSPACE_UL_addons_items(UIList):

    @staticmethod
    def _ui_label_from_addon(addon):
        # Return: `Category: Addon Name` when the add-on is known, otherwise it's module name.
        import addon_utils
        module = WORKSPACE_PT_addons.addon_map.get(addon.module)
        if not module:
            return addon.module
        bl_info = addon_utils.module_bl_info(module)
        return "{:s}: {:s}".format(iface_(bl_info["category"]), iface_(bl_info["name"]))

    @staticmethod
    def _filter_addons_by_category_name(pattern, bitflag, addons, reverse=False):
        # Set FILTER_ITEM for addons which category and name matches filter_name one (case-insensitive).
        # pattern is the filtering pattern.
        # return a list of flags based on given bit flag, or an empty list if no pattern is given
        # or list addons is empty.

        if not pattern or not addons:  # Empty pattern or list = no filtering!
            return []

        import fnmatch
        import re

        # Implicitly add heading/trailing wildcards.
        pattern_regex = re.compile(fnmatch.translate("*" + pattern + "*"), re.IGNORECASE)

        flags = [0] * len(addons)

        for i, addon in enumerate(addons):
            name = WORKSPACE_UL_addons_items._ui_label_from_addon(addon)
            # This is similar to a logical XOR.
            if bool(name and pattern_regex.match(name)) is not reverse:
                flags[i] |= bitflag
        return flags

    @staticmethod
    def _sort_addons_by_category_name(addons):
        # Re-order addons using their categories and names (case-insensitive).
        # return a list mapping org_idx -> new_idx, or an empty list if no sorting has been done.
        _sort = [(idx, WORKSPACE_UL_addons_items._ui_label_from_addon(addon)) for idx, addon in enumerate(addons)]
        return bpy.types.UI_UL_list.sort_items_helper(_sort, lambda e: e[1].lower())

    def filter_items(self, _context, data, property):
        addons = getattr(data, property)
        flags = []
        indices = []

        # Filtering by category and name
        if self.filter_name:
            flags = self._filter_addons_by_category_name(
                self.filter_name, self.bitflag_filter_item, addons, reverse=self.use_filter_invert,
            )
        if not flags:
            flags = [self.bitflag_filter_item] * len(addons)
        # Filer addons without registered modules
        for idx, addon in enumerate(addons):
            if not WORKSPACE_PT_addons.addon_map.get(addon.module):
                flags[idx] = 0
        if self.use_filter_sort_alpha:
            indices = self._sort_addons_by_category_name(addons)
        return flags, indices

    def draw_item(self, context, layout, _data, addon, _icon, _active_data, _active_propname, _index):
        row = layout.row()
        row.active = context.workspace.use_filter_by_owner
        row.emboss = 'NONE'
        row.label(text=WORKSPACE_UL_addons_items._ui_label_from_addon(addon))
        row = row.row()
        row.alignment = 'RIGHT'
        is_enabled = addon.module in WORKSPACE_PT_addons.owner_ids
        row.operator(
            "wm.owner_disable" if is_enabled else "wm.owner_enable",
            icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT',
            text="",
        ).owner_id = addon.module


class WORKSPACE_PT_custom_props(WorkSpaceButtonsPanel, PropertyPanel, Panel):
    bl_parent_id = "WORKSPACE_PT_main"

    _context_path = "workspace"
    _property_type = bpy.types.WorkSpace


classes = (
    WORKSPACE_UL_addons_items,

    WORKSPACE_PT_main,
    WORKSPACE_PT_addons,
    WORKSPACE_PT_custom_props,
)


bpy.types.WorkSpace.active_addon = bpy.props.IntProperty(
    name="Active Add-on",
    description="Active Add-on in the Workspace Add-ons filter",
)


if __name__ == "__main__":  # only for live edit.
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)
