# Copyright (c) 2024 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
import json
from conanbase import ConanBase, copy, os


def _add_package_dependency(name, version):
    with open('package.json', 'r') as f:
        pkg = json.load(f)
    pkg['dependencies'][name] = version
    with open('package.json', 'w') as f:
        json.dump(pkg, f, indent=2)
        f.write('\n')


def _add_echarts_gl_to_dev():
    with open('package.json', 'r') as f:
        pkg = json.load(f)
    pkg.setdefault('devDependencies', {})['echarts-gl'] = '2.1.0'
    # 注入的包不进 lock,echarts-gl 对 claygl 的 ^1.2.1 会各环境各自解析,这里一并钉死
    pkg['devDependencies']['claygl'] = '1.3.0'
    with open('package.json', 'w') as f:
        json.dump(pkg, f, indent=2)
        f.write('\n')


required_conan_version = ">=1.60.0"

TS_HEADER = """// Copyright (c) 2024 Huawei Technologies Co., Ltd.
// openUBMC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//        http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.

"""

DEFAULT_FEATURE_FLAGS = {
    'LDAP_PAGE_ENABLED': True,
    'ENERGY_PAGE_ENABLED': True,
    'VTPCM_PAGE_ENABLED': False,
    'WEBVNC_PAGE_ENABLED': False,

    'PRODUCT_INFO_ENABLED': True,
    'PROCESSOR_ENABLED': True,
    'MEMORY_ENABLED': True,
    'NETWORK_ADAPTER_ENABLED': True,
    'THRESHOLD_SENSOR_ENABLED': True,
    'DISCRETE_SENSOR_ENABLED': True,
    'FRU_ENABLED': True,
    'ASSEMBLY_ENABLED': True,
    'OTHER_ENABLED': True,
    'MONITOR_ENABLED': True,
    'STORAGE_ENABLED': True,

    'POWER_INFO_ENABLED': True,
    'POWER_CAP_ENABLED': True,
    'POWER_CONVERTER_ENABLED': True,
    'POWER_CONTROL_ENABLED': True,
    'POWER_SUPPLY_MODE_ENABLED': True,
    'POWER_ENERGY_ENABLED': True,
    'POWER_ENERGY_SAVING_ENABLED': True,
    'DEEP_SLEEP_ENABLED': True,
    'COMPONENT_POWER_HISTORY_ENABLED': True,
    'FAN_CALC_MODEL_MANAGEMENT_ENABLED': True,
    'FAN_SENSOR_ENABLED': True,
    'FAN_ENABLED': True,
    'THERMAL_ENABLED': True,

    'BIOS_ENABLED': True,
    'BIOS_CPU_ENABLED': True,
    'BIOS_SETTINGS_ENABLED': True,
    'BIOS_EXPORT_ENABLED': True,

    'PARTITY_ENABLED': True,
    'POD_ENABLED': True,

    'REPORT_ENABLED': True,
    'TRAP_ENABLED': True,
    'VIDEO_ENABLED': True,
    'SYSTEM_LOG_ENABLED': True,
    'DIAGNOSTIC_METRICS_ENABLED': True,
    'BMC_LOG_ENABLED': True,
    'WORK_RECORD_ENABLED': True,
    'ASSET_ENABLED': True,
    'ASSET_CHANGE_ENABLED': True,
    'TRUSTED_SUPPLY_CHAIN_ENABLED': True,
    'RETIRE_ENABLED': True,
    'OBSERVE_ENABLED': True,

    'KVM_ENABLED': True,
    'VNC_ENABLED': True,

    'LOCAL_USER_ENABLED': True,
    'LDAP_USER_ENABLED': True,
    'TWO_FACTOR_ENABLED': True,
    'ONLINE_USER_ENABLED': True,
    'SECURITY_ENABLED': True,

    'CER_ENABLED': True,
    'TPCM_ENABLED': True,
    'KERBEROS_ENABLED': True,

    'PORT_ENABLED': True,
    'WEB_ENABLED': True,
    'VMM_ENABLED': True,
    'SNMP_ENABLED': True,
    'NETWORK_ENABLED': True,
    'NTP_ENABLED': True,
    'UPGRADE_ENABLED': True,
    'UPGRADE_REPO_ENABLED': True,
    'CONFIG_ENABLED': True,
    'CONFIG_PARTS_RECOVERY_ENABLED': True,
    'LANGUAGE_ENABLED': True,
    'LICENSE_ENABLED': True,

    'BMA_ENABLED': True,
    'IBMA_ENABLED': True,
    'SP_ENABLED': True,
    'USB_ENABLED': True,
}

SERVICE_OPTION_FLAG_MAP = {
    'ldap_enabled': 'LDAP_PAGE_ENABLED',
    'energy_enabled': 'ENERGY_PAGE_ENABLED',
    'vtpcm_enabled': 'VTPCM_PAGE_ENABLED',
    'webvnc_enabled': 'WEBVNC_PAGE_ENABLED',
    'trap_enabled': 'TRAP_ENABLED',
    'feature_asset': 'ASSET_ENABLED',
    'asset_change_enabled': 'ASSET_CHANGE_ENABLED',
    'feature_trusted_supply_chain': 'TRUSTED_SUPPLY_CHAIN_ENABLED',
    'feature_retire': 'RETIRE_ENABLED',
    'processor_enabled': 'PROCESSOR_ENABLED',
    'memory_enabled': 'MEMORY_ENABLED',
    'network_adapter_enabled': 'NETWORK_ADAPTER_ENABLED',
    'fru_enabled': 'FRU_ENABLED',
    'assembly_enabled': 'ASSEMBLY_ENABLED',
    'other_enabled': 'OTHER_ENABLED',
    'bios_cpu_enabled': 'BIOS_CPU_ENABLED',
    'snmp_enabled': 'SNMP_ENABLED',
    'feature_energy_efficiency': (
        'DEEP_SLEEP_ENABLED',
        'COMPONENT_POWER_HISTORY_ENABLED',
    ),
    'feature_diagnostic_metrics': 'DIAGNOSTIC_METRICS_ENABLED',
    'feature_license': 'LICENSE_ENABLED',
    'feature_usb_entry': 'USB_ENABLED',
    'feature_observe': 'OBSERVE_ENABLED',
    'fan_calc_model_management_enabled': 'FAN_CALC_MODEL_MANAGEMENT_ENABLED',
    'fan_sensor_enabled': 'FAN_SENSOR_ENABLED',
    'power_energy_enabled': 'POWER_ENERGY_ENABLED',
    'power_energy_saving_enabled': 'POWER_ENERGY_SAVING_ENABLED',
    'upgrade_repo_enabled': 'UPGRADE_REPO_ENABLED',
    'config_parts_recovery_enabled': 'CONFIG_PARTS_RECOVERY_ENABLED',
    'ibma_enabled': 'IBMA_ENABLED',
    'sp_enabled': 'SP_ENABLED',
}


def named_import(name, source):
    return {'type': 'named', 'name': name, 'source': source}


def default_import(name, source):
    return {'type': 'default', 'name': name, 'source': source}


IMPORTS = {
    'certificateRoutes': default_import(
        'certificateRoutes',
        '@/apps/app-bmc/router/navigate/user/certificate/certificate-router',
    ),
    'assetChangeGuard': named_import('assetChangeGuard', '@/apps/app-bmc/guard/assetChange.guard'),
    'forbidGuard': named_import('forbidGuard', '@/apps/app-bmc/guard/forbid.guard'),
    'ibmaGuard': named_import('ibmaGuard', '@/apps/app-bmc/guard/ibma.guard'),
    'ibmcManageMentSecondMenu': named_import('ibmcManageMentSecondMenu', '@/apps/app-bmc/store/menu-list'),
    'kvmMultiGuard': named_import('kvmMultiGuard', '@/apps/app-bmc/guard/kvmMulti.guard'),
    'langGuard': named_import('langGuard', '@/apps/app-bmc/guard/lang.guard'),
    'licenseGuard': named_import('licenseGuard', '@/apps/app-bmc/guard/license.guard'),
    'securityRoutes': default_import(
        'securityRoutes',
        '@/apps/app-bmc/router/navigate/user/security/security-router',
    ),
    'snmpGuard': named_import('snmpGuard', '@/apps/app-bmc/guard/snmp.guard'),
    'spGuard': named_import('spGuard', '@/apps/app-bmc/guard/sp.guard'),
    'spRoutes': default_import('spRoutes', '@/apps/app-bmc/router/navigate/manager/sp/sp.router'),
    'tpcmGuard': named_import('tpcmGuard', '@/apps/app-bmc/guard/tpcm.guard'),
    'twoFactorGuard': named_import('twoFactorGuard', '@/apps/app-bmc/guard/twoFactor.guard'),
    'twoFactorRoutes': default_import(
        'twoFactorRoutes',
        '@/apps/app-bmc/router/navigate/user/twofactor/twofactor-router',
    ),
    'usbGuard': named_import('usbGuard', '@/apps/app-bmc/guard/usb.guard'),
    'vmmGuard': named_import('vmmGuard', '@/apps/app-bmc/guard/vmm.guard'),
    'vncGuard': named_import('vncGuard', '@/apps/app-bmc/guard/vnc.guard'),
}


def lazy(path):
    return f"() => import('{path}')"


def route(flag=None, imports=(), **entries):
    return {
        'entries': tuple(entries.items()),
        'flag': flag,
        'imports': imports,
    }


FEATURE_ROUTE_GROUPS = {
    'appFeatureRoutes': [
        route(
            flag='WEBVNC_PAGE_ENABLED',
            path="'/vnc_h5'",
            name="'VNC'",
            component=lazy('@/pages/VirtualControl/VncH5/VncH5.vue'),
        ),
    ],
    'assetRoutes': [
        route(
            flag='RETIRE_ENABLED',
            path="'/navigate/maintenance/asset-maintance/asset-retire'",
            component=lazy('@/pages/Maintance/AssetMaintance/components/AssetRetire.vue'),
        ),
        route(
            flag='ASSET_ENABLED',
            path="'/navigate/maintenance/asset-maintance/asset-inventory'",
            component=lazy('@/pages/Maintance/AssetMaintance/components/AssetInventory.vue'),
        ),
        route(
            flag='ASSET_CHANGE_ENABLED',
            imports=('assetChangeGuard',),
            path="'/navigate/maintenance/asset-maintance/asset-change'",
            component=lazy('@/pages/Maintance/AssetMaintance/components/AssetChange.vue'),
            beforeEnter='[assetChangeGuard]',
        ),
        route(
            flag='TRUSTED_SUPPLY_CHAIN_ENABLED',
            imports=('forbidGuard',),
            path="'/navigate/maintenance/asset-maintance/supply-chain-config'",
            component=lazy('@/pages/Maintance/AssetMaintance/components/SupplyChainConfig.vue'),
            beforeEnter='[forbidGuard]',
        ),
    ],
    'serviceRoutes': [
        route(
            flag='PORT_ENABLED',
            path="'/navigate/service/port'",
            component=lazy('@/pages/Service/Port/Port.vue'),
        ),
        route(
            flag='WEB_ENABLED',
            path="'/navigate/service/web'",
            component=lazy('@/pages/Service/Web/Web.vue'),
        ),
        route(
            imports=('kvmMultiGuard',),
            path="'/navigate/service/kvm'",
            component=lazy('@/pages/Service/Kvm/Kvm.vue'),
            beforeEnter='[kvmMultiGuard]',
        ),
        route(
            flag='VMM_ENABLED',
            imports=('vmmGuard',),
            path="'/navigate/service/vmm'",
            component=lazy('@/pages/Service/Vmm/Vmm.vue'),
            beforeEnter='[vmmGuard]',
        ),
        route(
            flag='VNC_ENABLED',
            imports=('vncGuard',),
            path="'/navigate/service/vnc'",
            component=lazy('@/pages/Service/Vnc/Vnc.vue'),
            beforeEnter='[vncGuard]',
        ),
        route(
            flag='SNMP_ENABLED',
            imports=('snmpGuard',),
            path="'/navigate/service/snmp'",
            component=lazy('@/pages/Service/Snmp/Snmp.vue'),
            beforeEnter='[snmpGuard]',
        ),
        route(
            path="'/navigate/service/ipmi'",
            component=lazy('@/pages/Service/IPMI/IPMI.vue'),
        ),
    ],
    'userRoutes': [
        route(
            path="'/navigate/user/local-users'",
            component=lazy('@/pages/User/Localuser/Localuser.vue'),
        ),
        route(
            flag='LDAP_USER_ENABLED',
            imports=('twoFactorGuard',),
            path="'/navigate/user/ldap'",
            component=lazy('@/pages/User/Ldap/Ldap.vue'),
            beforeEnter='[twoFactorGuard]',
        ),
        route(
            imports=('forbidGuard',),
            path="'/navigate/user/kerberos'",
            component=lazy('@/pages/User/Kerberos/Kerberos.vue'),
            beforeEnter='[forbidGuard]',
        ),
        route(
            imports=('twoFactorRoutes', 'twoFactorGuard'),
            path="'/navigate/user/two-factor'",
            component=lazy('@/pages/User/TwoFactor/TwoFactor.vue'),
            redirect="'/navigate/user/two-factor/client'",
            children='twoFactorRoutes',
            beforeEnter='[twoFactorGuard]',
        ),
        route(
            path="'/navigate/user/online-users'",
            component=lazy('@/pages/User/OnlineUser/OnlineUser.vue'),
        ),
        route(
            imports=('securityRoutes',),
            path="'/navigate/user/security'",
            component=lazy('@/pages/User/Security/Security.vue'),
            redirect='securityRoutes[0].path',
            children='securityRoutes',
        ),
        route(
            flag='TPCM_ENABLED',
            imports=('tpcmGuard',),
            path="'/navigate/user/tpcm'",
            component=lazy('@/pages/User/Tpcm/tpcm.vue'),
            beforeEnter='[tpcmGuard]',
        ),
        route(
            imports=('certificateRoutes',),
            path="'/navigate/user/certificate'",
            component=lazy('@/pages/User/Certificate/Certificate.vue'),
            redirect='certificateRoutes[0].path',
            children='certificateRoutes',
        ),
    ],
    'managerRoutes': [
        route(
            imports=('ibmcManageMentSecondMenu',),
            path='ibmcManageMentSecondMenu[0].router',
            component=lazy('@/pages/Manager/Network/Network.vue'),
        ),
        route(
            flag='NTP_ENABLED',
            imports=('ibmcManageMentSecondMenu',),
            path='ibmcManageMentSecondMenu[1].router',
            component=lazy('@/pages/Manager/Ntp/Ntp.vue'),
        ),
        route(
            flag='UPGRADE_ENABLED',
            imports=('ibmcManageMentSecondMenu',),
            path='ibmcManageMentSecondMenu[2].router',
            component=lazy('@/pages/Manager/Upgrade/Upgrade.vue'),
        ),
        route(
            flag='CONFIG_ENABLED',
            imports=('ibmcManageMentSecondMenu',),
            path='ibmcManageMentSecondMenu[3].router',
            component=lazy('@/pages/Manager/ConfigUpdate/ConfigUpdate.vue'),
        ),
        route(
            flag='LANGUAGE_ENABLED',
            imports=('ibmcManageMentSecondMenu', 'langGuard'),
            path='ibmcManageMentSecondMenu[4].router',
            component=lazy('@/pages/Manager/Language/Language.vue'),
            beforeEnter='[langGuard]',
        ),
        route(
            flag='LICENSE_ENABLED',
            imports=('ibmcManageMentSecondMenu', 'licenseGuard'),
            path='ibmcManageMentSecondMenu[5].router',
            component=lazy('@/pages/Manager/License/License.vue'),
            beforeEnter='[licenseGuard]',
        ),
        route(
            flag='IBMA_ENABLED',
            imports=('ibmcManageMentSecondMenu', 'ibmaGuard'),
            path='ibmcManageMentSecondMenu[6].router',
            component=lazy('@/pages/Manager/Ibma/Ibma.vue'),
            beforeEnter='[ibmaGuard]',
        ),
        route(
            flag='SP_ENABLED',
            imports=('ibmcManageMentSecondMenu', 'spGuard', 'spRoutes'),
            path='ibmcManageMentSecondMenu[7].router',
            component=lazy('@/pages/Manager/Sp/Sp.vue'),
            redirect="'/navigate/manager/sp/sp-manage'",
            children='spRoutes',
            beforeEnter='[spGuard]',
        ),
        route(
            flag='USB_ENABLED',
            imports=('ibmcManageMentSecondMenu', 'usbGuard'),
            path='ibmcManageMentSecondMenu[8].router',
            component=lazy('@/pages/Manager/Usb/Usb.vue'),
            beforeEnter='[usbGuard]',
        ),
        route(
            path="''",
            redirect="'/navigate/manager/network'",
        ),
    ],
}


def generate_configure_file(config_flags):
    lines = [TS_HEADER]
    for flag_name in sorted(config_flags.keys()):
        lines.append(f"export const {flag_name} = {str(config_flags[flag_name]).lower()};")
    content = "\n".join(lines) + "\n"
    with open('src/model/configure.generated.ts', 'w') as fo:
        fo.write(content)


def _format_route_array(routes):
    if not routes:
        return "[]"
    return "[\n" + ",\n".join(routes) + ",\n]"


def _enabled(config_flags, flag_name):
    return flag_name is None or bool(config_flags.get(flag_name, False))


def _select_routes(config_flags, route_specs):
    return [route_spec for route_spec in route_specs if _enabled(config_flags, route_spec.get('flag'))]


def _render_import(import_def):
    if import_def['type'] == 'default':
        return f"import {import_def['name']} from '{import_def['source']}';"
    return f"import {{ {import_def['name']} }} from '{import_def['source']}';"


def _render_route(route_spec):
    lines = ["  {"]
    lines.extend(f"    {key}: {value}," for key, value in route_spec['entries'])
    lines.append("  }")
    return "\n".join(lines)


def _collect_route_imports(routes_by_group):
    imports = ["import { RouteRecordRaw } from 'vue-router';"]
    seen = set()
    for routes in routes_by_group.values():
        for route_spec in routes:
            for import_name in route_spec.get('imports', ()):
                if import_name in seen:
                    continue
                imports.append(_render_import(IMPORTS[import_name]))
                seen.add(import_name)
    return imports


def generate_feature_routes_file(config_flags):
    routes_by_group = {
        group_name: _select_routes(config_flags, route_specs)
        for group_name, route_specs in FEATURE_ROUTE_GROUPS.items()
    }

    content = TS_HEADER
    content += "\n".join(_collect_route_imports(routes_by_group))
    content += "\n\n"
    for group_name, routes in routes_by_group.items():
        rendered_routes = [_render_route(route_spec) for route_spec in routes]
        content += f"export const {group_name}: Array<RouteRecordRaw> = {_format_route_array(rendered_routes)};\n\n"

    with open('src/apps/app-bmc/router/feature-routes.generated.ts', 'w') as fo:
        fo.write(content.rstrip() + "\n")


def _get_bool_option(options, option_name, default):
    if hasattr(options, option_name):
        return bool(getattr(options, option_name))
    return default


def _load_service_json_options():
    try:
        with open('mds/service.json', 'r') as fi:
            service = json.load(fi)
        options = service.get('options', {})
        option_values = {}
        default_values = {}
        for option_name, option_def in options.items():
            if not isinstance(option_def, dict):
                continue
            if 'option' in option_def:
                option_values[option_name] = option_def['option']
            if 'default' in option_def:
                default_values[option_name] = option_def['default']
        return option_values, default_values
    except Exception:
        return {}, {}


def _load_service_json_option_defaults():
    return _load_service_json_options()[1]


def build_webvnc_enabled_configure():
    _add_package_dependency('@novnc/novnc', '1.3.0')


def build_three_dui_enabled_configure():
    _add_package_dependency('three', '0.178.0')

    home_src = ""
    home_path = 'src/apps/app-bmc/Navigate/Home/Home.vue'
    with open(home_path, 'r') as fi:
        home_src = fi.read()

    home_src = home_src.replace(
        "@/pages/Home/Home.vue",
        "@/pages/Home/HomeReconstructed.vue",
    )
    with open(home_path, 'w') as fo:
        fo.write(home_src)


SERVICE_JSON_OPTIONS, SERVICE_JSON_DEFAULT_OPTIONS = _load_service_json_options()

WEBUI_FALLBACK_OPTIONS = {
    'ldap_enabled': [True, False],
    'energy_enabled': [True, False],
    'vtpcm_enabled': [True, False],
    'webvnc_enabled': [True, False],
    'three_dui_enabled': [True, False],
    'trap_enabled': [True, False],
    'feature_asset': [True, False],
    'asset_change_enabled': [True, False],
    'feature_trusted_supply_chain': [True, False],
    'feature_retire': [True, False],
    'processor_enabled': [True, False],
    'memory_enabled': [True, False],
    'network_adapter_enabled': [True, False],
    'fru_enabled': [True, False],
    'assembly_enabled': [True, False],
    'other_enabled': [True, False],
    'bios_cpu_enabled': [True, False],
    'snmp_enabled': [True, False],
    'feature_energy_efficiency': [True, False],
    'feature_diagnostic_metrics': [True, False],
    'feature_license': [True, False],
    'feature_usb_entry': [True, False],
    'feature_observe': [True, False],
    'fan_calc_model_management_enabled': [True, False],
    'fan_sensor_enabled': [True, False],
    'power_energy_enabled': [True, False],
    'power_energy_saving_enabled': [True, False],
    'upgrade_repo_enabled': [True, False],
    'config_parts_recovery_enabled': [True, False],
    'ibma_enabled': [True, False],
    'sp_enabled': [True, False],
}

WEBUI_FALLBACK_DEFAULT_OPTIONS = {
    'ldap_enabled': True,
    'energy_enabled': True,
    'vtpcm_enabled': False,
    'webvnc_enabled': False,
    'three_dui_enabled': False,
    'trap_enabled': True,
    'feature_asset': True,
    'asset_change_enabled': True,
    'feature_trusted_supply_chain': True,
    'feature_retire': True,
    'processor_enabled': True,
    'memory_enabled': True,
    'network_adapter_enabled': True,
    'fru_enabled': True,
    'assembly_enabled': True,
    'other_enabled': True,
    'bios_cpu_enabled': True,
    'snmp_enabled': True,
    'feature_energy_efficiency': True,
    'feature_diagnostic_metrics': True,
    'feature_license': True,
    'feature_usb_entry': True,
    'feature_observe': True,
    'fan_calc_model_management_enabled': True,
    'fan_sensor_enabled': True,
    'power_energy_enabled': True,
    'power_energy_saving_enabled': True,
    'upgrade_repo_enabled': True,
    'config_parts_recovery_enabled': True,
    'ibma_enabled': True,
    'sp_enabled': True,
}


def _merge_conan_dict(*dicts):
    values = {}
    for dict_value in dicts:
        if isinstance(dict_value, dict):
            values.update(dict_value)
    return values


class WebUIConan(ConanBase):
    name = "webui"
    license = "BSD licence"
    generators = "VirtualBuildEnv"
    homepage = "https://www.huawei.com/"
    description = ""
    chost = None
    settings = "arch"
    exports = "mds/service.json"
    options = _merge_conan_dict(
        WEBUI_FALLBACK_OPTIONS,
        SERVICE_JSON_OPTIONS,
        getattr(ConanBase, 'options', {}),
    )
    default_options = _merge_conan_dict(
        WEBUI_FALLBACK_DEFAULT_OPTIONS,
        SERVICE_JSON_DEFAULT_OPTIONS,
        getattr(ConanBase, 'default_options', {}),
    )

    def build(self):
        config_flags = dict(DEFAULT_FEATURE_FLAGS)
        service_defaults = _load_service_json_option_defaults()

        for option_name, flag_names in SERVICE_OPTION_FLAG_MAP.items():
            if not isinstance(flag_names, tuple):
                flag_names = (flag_names,)
            for flag_name in flag_names:
                default_value = service_defaults.get(option_name, config_flags[flag_name])
                config_flags[flag_name] = _get_bool_option(
                    self.options,
                    option_name,
                    default_value,
                )

        generate_configure_file(config_flags)
        generate_feature_routes_file(config_flags)

        webvnc_enabled = _get_bool_option(self.options, 'webvnc_enabled', False)
        three_dui_enabled = _get_bool_option(self.options, 'three_dui_enabled', False)

        if webvnc_enabled:
            build_webvnc_enabled_configure()
        if three_dui_enabled:
            build_three_dui_enabled_configure()
        _add_echarts_gl_to_dev()
        self.run(f"npm install")
        self.run(f"npm run build")

    def package(self):
        self.run(f"rm -rf node_modules")
        self.run(f"npm install --production")
        if os.path.isfile("public/permissions.ini"):
            copy(self, "permissions.ini", src=os.path.join(self.source_folder, "public"),
                dst=self.package_folder, keep_path=True)
        # 排除文件
        three_dui_enabled = self.options.three_dui_enabled
        excludes = None if three_dui_enabled else (
            "**/server_model.*",
            "**/server_model/**",
        )
        # 切换dist为工作目录
        copy(self, "*", src=os.path.join(self.source_folder, "dist"),
            dst=os.path.join(self.package_folder, "opt/bmc/web/htdocs/"),
            excludes=excludes,)

    def layout(self):
        pass