import dash
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import feffery_antd_components as fac
from jsonpath_ng import parse
from flask import json, session
from collections import OrderedDict

from server import app
import views
from utils.tree_tool import find_title_by_key, find_modules_by_key, find_href_by_key,  find_parents


@app.callback(
    [Output('tabs-container', 'items', allow_duplicate=True),
     Output('tabs-container', 'activeKey', allow_duplicate=True)],
    [Input('index-side-menu', 'currentKey'),
     Input('tabs-container', 'tabCloseCounts')],
    [State('tabs-container', 'latestDeletePane'),
     State('tabs-container', 'items'),
     State('tabs-container', 'activeKey'),
     State('menu-info-store-container', 'data'),
     State('menu-list-store-container', 'data')],
    prevent_initial_call=True
)
def handle_tab_switch_and_create(currentKey, tabCloseCounts, latestDeletePane, origin_items, activeKey, menu_info, menu_list):
    """
    这个回调函数用于处理标签页子项的新建、切换及删除
    具体策略：
        1.当左侧某个菜单项被新选中，且右侧标签页子项尚未包含此项时，新建并切换
        2.当左侧某个菜单项被新选中，且右侧标签页子项已包含此项时，切换
        3.当右侧标签页子项某项被删除时，销毁对应标签页的同时切换回最后新增的标签页
    """

    trigger_id = dash.ctx.triggered_id

    # 基于jsonpath对各标签页子项中所有已有记录的nClicks参数重置为None
    # 以避免每次新的items返回给标签页重新渲染后，
    # 先前已更新为非None的按钮的nClicks误触发通知弹出回调
    parser = parse('$..nClicks')
    origin_items = parser.update(origin_items, None)
    new_items = dash.Patch()

    if trigger_id == 'index-side-menu':

        # 判断当前新选中的菜单栏项对应标签页是否已创建
        if currentKey in [item['key'] for item in origin_items]:
            return [
                dash.no_update,
                currentKey
            ]

        if currentKey == '个人资料':
            menu_title = '个人资料'
            button_perms = []
            role_perms = []
            menu_modules = 'system.user.profile'
        else:
            menu_title = find_title_by_key(menu_info.get('menu_info'), currentKey)
            button_perms = [item.get('perms') for item in menu_list.get('menu_list') if str(item.get('parent_id')) == currentKey]
            role_perms = [item.get('role_key') for item in session.get('role_info')]
            # 判断当前选中的菜单栏项是否存在module，如果有，则动态导入module，否则返回404页面
            menu_modules = find_modules_by_key(menu_info.get('menu_info'), currentKey)

        for index, item in enumerate(origin_items):
            if {'key': '关闭右侧', 'label': '关闭右侧', 'icon': 'antd-arrow-right'} not in item['contextMenu']:
                item['contextMenu'].insert(-1, {
                    'key': '关闭右侧',
                    'label': '关闭右侧',
                    'icon': 'antd-arrow-right'
                })
            new_items[index]['contextMenu'] = item['contextMenu']
        context_menu = [
            {
                'key': '刷新页面',
                'label': '刷新页面',
                'icon': 'antd-reload'
            },
            {
                'key': '关闭当前',
                'label': '关闭当前',
                'icon': 'antd-close'
            },
            {
                'key': '关闭其他',
                'label': '关闭其他',
                'icon': 'antd-close-circle'
            },
            {
                'key': '全部关闭',
                'label': '全部关闭',
                'icon': 'antd-close-circle'
            }
        ]
        if len(origin_items) != 1:
            context_menu.insert(-1, {
                'key': '关闭左侧',
                'label': '关闭左侧',
                'icon': 'antd-arrow-left'
            })
        if menu_modules:
            if menu_modules == 'link':
                raise PreventUpdate
            else:
                # 否则追加子项返回
                # 其中若各标签页内元素类似，则推荐配合模式匹配构建交互逻辑
                new_items.append(
                    {
                        'label': menu_title,
                        'key': currentKey,
                        'children': eval('views.' + menu_modules + '.render(button_perms=button_perms, role_perms=role_perms)'),
                        'contextMenu': context_menu
                    }
                )
        else:
            new_items.append(
                {
                    'label': menu_title,
                    'key': currentKey,
                    'children': fac.AntdResult(
                        status='404',
                        title='页面不存在',
                        subTitle='请先配置该路由的页面',
                        style={
                            'paddingBottom': 0,
                            'paddingTop': 0
                        }
                    ),
                    'contextMenu': context_menu
                }
            )

        return [
            new_items,
            currentKey
        ]

    elif trigger_id == 'tabs-container':

        # 如果删除的是当前标签页则回到最后新增的标签页，否则保持当前标签页不变
        for index, item in enumerate(origin_items):
            if item['key'] == latestDeletePane:
                context_menu = [
                    {
                        'key': '刷新页面',
                        'label': '刷新页面',
                        'icon': 'antd-reload'
                    },
                    {
                        'key': '关闭其他',
                        'label': '关闭其他',
                        'icon': 'antd-close-circle'
                    },
                    {
                        'key': '全部关闭',
                        'label': '全部关闭',
                        'icon': 'antd-close-circle'
                    }
                ]
                if index == 1:
                    if len(origin_items) == 2:
                        new_items[0]['contextMenu'] = context_menu
                    else:
                        origin_items[2]['contextMenu'].remove({
                            'key': '关闭左侧',
                            'label': '关闭左侧',
                            'icon': 'antd-arrow-left'
                        })
                        new_items[2]['contextMenu'] = origin_items[2]['contextMenu']
                elif index == 2:
                    if len(origin_items) == 3:
                        origin_items[1]['contextMenu'].remove({
                            'key': '关闭右侧',
                            'label': '关闭右侧',
                            'icon': 'antd-arrow-right'
                        })
                        new_items[1]['contextMenu'] = origin_items[1]['contextMenu']
                else:
                    if index == len(origin_items) - 1:
                        new_items[index - 1]['contextMenu'] = item['contextMenu']
                del new_items[index]
                break
        new_origin_items = [
            item for item in
            origin_items if item['key'] != latestDeletePane
        ]

        return [
            new_items,
            new_origin_items[-1]['key'] if activeKey == latestDeletePane else activeKey
        ]

    raise PreventUpdate


@app.callback(
    [Output('tabs-container', 'items', allow_duplicate=True),
     Output('tabs-container', 'activeKey', allow_duplicate=True),
     Output('trigger-reload-output', 'reload', allow_duplicate=True)],
    Input('tabs-container', 'clickedContextMenu'),
    [State('tabs-container', 'items'),
     State('tabs-container', 'activeKey')],
    prevent_initial_call=True
)
def handle_via_context_menu(clickedContextMenu, origin_items, activeKey):
    """
    基于标签页标题右键菜单的额外标签页控制
    """
    if clickedContextMenu['menuKey'] == '刷新页面':

        return [
            dash.no_update,
            dash.no_update,
            True
        ]

    if '关闭' in clickedContextMenu['menuKey']:
        new_items = dash.Patch()
        if clickedContextMenu['menuKey'] == '关闭当前':
            for index, item in enumerate(origin_items):
                if item['key'] == clickedContextMenu['tabKey']:
                    context_menu = [
                        {
                            'key': '刷新页面',
                            'label': '刷新页面',
                            'icon': 'antd-reload'
                        },
                        {
                            'key': '关闭其他',
                            'label': '关闭其他',
                            'icon': 'antd-close-circle'
                        },
                        {
                            'key': '全部关闭',
                            'label': '全部关闭',
                            'icon': 'antd-close-circle'
                        }
                    ]
                    if index == 1:
                        if len(origin_items) == 2:
                            new_items[0]['contextMenu'] = context_menu
                        else:
                            origin_items[2]['contextMenu'].remove({
                                'key': '关闭左侧',
                                'label': '关闭左侧',
                                'icon': 'antd-arrow-left'
                            })
                            new_items[2]['contextMenu'] = origin_items[2]['contextMenu']
                    elif index == 2:
                        if len(origin_items) == 3:
                            origin_items[1]['contextMenu'].remove({
                                'key': '关闭右侧',
                                'label': '关闭右侧',
                                'icon': 'antd-arrow-right'
                            })
                            new_items[1]['contextMenu'] = origin_items[1]['contextMenu']
                    else:
                        if index == len(origin_items) - 1:
                            new_items[index - 1]['contextMenu'] = item['contextMenu']
                    del new_items[index]
                    break
            new_origin_items = [
                item for item in
                origin_items if item['key'] != clickedContextMenu['tabKey']
            ]

            return [
                new_items,
                new_origin_items[-1]['key'] if activeKey == clickedContextMenu['tabKey'] else activeKey,
                dash.no_update
            ]

        elif clickedContextMenu['menuKey'] == '关闭其他':
            current_index = 0
            for index, item in enumerate(origin_items):
                if item['key'] == clickedContextMenu['tabKey']:
                    current_index = index
            for i in range(1, current_index):
                del new_items[1]
            for j in range(current_index+1, len(origin_items)+1):
                del new_items[2]
            context_menu = [
                {
                    'key': '刷新页面',
                    'label': '刷新页面',
                    'icon': 'antd-reload'
                },
                {
                    'key': '关闭其他',
                    'label': '关闭其他',
                    'icon': 'antd-close-circle'
                },
                {
                    'key': '全部关闭',
                    'label': '全部关闭',
                    'icon': 'antd-close-circle'
                }
            ]
            if clickedContextMenu['tabKey'] == '首页':
                new_items[0]['contextMenu'] = context_menu
            else:
                context_menu.insert(1, {
                    'key': '关闭当前',
                    'label': '关闭当前',
                    'icon': 'antd-close'
                })
                new_items[1]['contextMenu'] = context_menu

            return [
                new_items,
                clickedContextMenu['tabKey'],
                dash.no_update
            ]

        elif clickedContextMenu['menuKey'] == '关闭左侧':
            current_index = 0
            for index, item in enumerate(origin_items):
                if item['key'] == clickedContextMenu['tabKey']:
                    current_index = index
                    item['contextMenu'].remove({
                        'key': '关闭左侧',
                        'label': '关闭左侧',
                        'icon': 'antd-arrow-left'
                    })
                    new_items[index]['contextMenu'] = item['contextMenu']
                    break
            for i in range(1, current_index):
                del new_items[1]

            return [
                new_items,
                clickedContextMenu['tabKey'],
                dash.no_update
            ]

        elif clickedContextMenu['menuKey'] == '关闭右侧':
            current_index = 0
            for index, item in enumerate(origin_items):
                if item['key'] == clickedContextMenu['tabKey']:
                    current_index = index
                    item['contextMenu'].remove({
                        'key': '关闭右侧',
                        'label': '关闭右侧',
                        'icon': 'antd-arrow-right'
                    })
                    new_items[index]['contextMenu'] = item['contextMenu']
                    break
            for i in range(current_index+1, len(origin_items)+1):
                del new_items[current_index+1]

            return [
                new_items,
                clickedContextMenu['tabKey'],
                dash.no_update
            ]

        for i in range(len(origin_items)):
            del new_items[1]
        new_items[0]['contextMenu'] = [
            {
                'key': '刷新页面',
                'label': '刷新页面',
                'icon': 'antd-reload'
            },
            {
                'key': '关闭其他',
                'label': '关闭其他',
                'icon': 'antd-close-circle'
            },
            {
                'key': '全部关闭',
                'label': '全部关闭',
                'icon': 'antd-close-circle'
            }
        ]
        # 否则则为全部关闭
        return [
            new_items,
            '首页',
            dash.no_update
        ]

    raise PreventUpdate


# 页首面包屑和hash回调
@app.callback(
    [Output('header-breadcrumb', 'items'),
     Output('dcc-url', 'pathname', allow_duplicate=True)],
    Input('tabs-container', 'activeKey'),
    State('menu-info-store-container', 'data'),
    prevent_initial_call=True
)
def get_current_breadcrumbs(active_key, menu_info):
    if active_key:

        if active_key == '首页':
            return [
                [
                    {
                        'title': '首页',
                        'icon': 'antd-dashboard',
                        'href': '/'
                    },
                ],
                '/'
            ]

        elif active_key == '个人资料':
            return [
                [
                    {
                        'title': '首页',
                        'icon': 'antd-dashboard',
                        'href': '/'
                    },
                    {
                        'title': '个人资料',
                    }
                ],
                '/user/profile'
            ]

        else:
            result = find_parents(menu_info.get('menu_info'), active_key)
            # 去除result的重复项
            parent_info = list(OrderedDict((json.dumps(d, ensure_ascii=False), d) for d in result).values())
            if parent_info:
                current_href = find_href_by_key(menu_info.get('menu_info'), active_key)

                return [
                    [
                        {
                            'title': '首页',
                            'icon': 'antd-dashboard',
                            'href': '/'
                        },
                    ] + parent_info,
                    current_href
                ]

    raise PreventUpdate
