import './core/app-telemetry.js';
import { createComponentRuntime } from './core/app-component-runtime.js';
import { warnOnce } from './core/app-dom.js';
import { initFlashAutoDismiss } from './components/app-flash-auto-dismiss.js';
import { initPasswordHints } from './components/app-password-hints.js';
import { initBadgeCopy } from './components/app-copy-badge.js';
import { initCopyField } from './components/app-copy-field.js';
import { initMultiSelectComponent } from './components/app-multiselect-init.js';
import { initTokenSelect } from './components/app-token-select.js';
import { initSidebarToggle } from './components/app-toggle-sidebar.js';
import { initAsidePanels } from './components/app-toggle-aside-panels.js';
import { initDetailsAsideToggle } from './components/app-toggle-details-aside.js';
import { initGlobalSearch } from './components/app-global-search.js';
import { initThemeControls } from './components/app-theme-toggle.js';
import { initContrastToggle } from './components/app-contrast-toggle.js';
import { initConfirmActions } from './components/app-confirm-actions.js';
import { initDetailsState } from './components/app-details-state.js';
import { initTenantSwitcher } from './components/app-tenant-switcher.js';
import { initCustomFieldOptionsToggle } from './components/app-custom-field-options-toggle.js';
import { initTenantSsoToggle } from './components/app-tenant-sso-toggle.js';
import { initTenantLdapToggle } from './components/app-tenant-ldap-toggle.js';
import { initTelemetrySettings } from './components/app-settings-telemetry.js';
import { initSettingsAudit } from './components/app-settings-audit.js';
import { initStandardDetailPages } from './components/app-standard-detail-page.js';
import { initAutoSubmit } from './components/app-auto-submit.js';
import { initTabs } from './components/app-tabs.js';
import { initListTabs } from './components/app-list-tabs.js';
import { initSessionWarning } from './components/app-session-warning.js';
import { initFsLightboxRefresh } from './components/app-fslightbox-refresh.js';
import { initFileUpload } from './components/app-file-upload.js';
import { initLookupFields } from './components/app-lookup-field.js';

const runtime = createComponentRuntime({
  root: document,
  configId: 'app-components',
});

const phaseRank = {
  early: 10,
  default: 50,
  late: 90,
};

const normalizePhase = (raw) => {
  const phase = String(raw || '').trim().toLowerCase();
  if (phase === 'early' || phase === 'default' || phase === 'late') {
    return phase;
  }
  return 'late';
};

const normalizeModuleRuntimeComponents = (value) => {
  if (!Array.isArray(value)) {
    return [];
  }

  return value
    .filter((item) => item && typeof item === 'object')
    .map((item) => {
      const key = String(item.key || '').trim();
      const moduleId = String(item.moduleId || '').trim();
      const componentName = String(item.componentName || '').trim() || (moduleId && key ? `${moduleId}.${key}` : '');
      const script = String(item.script || '').trim();
      const exportName = String(item.export || '').trim();
      const selector = String(item.selector || '').trim();
      const scope = String(item.scope || '').trim().toLowerCase();
      const configPath = String(item.configPath || '').trim();
      const phase = normalizePhase(item.phase);
      const order = Number.isFinite(Number(item.order)) ? Number(item.order) : 100;

      return {
        key,
        moduleId,
        componentName,
        script,
        exportName,
        selector,
        scope,
        configPath,
        phase,
        order,
      };
    })
    .filter((item) => item.componentName !== '' && item.script !== '')
    .sort((a, b) => {
      const phaseCmp = (phaseRank[a.phase] || phaseRank.late) - (phaseRank[b.phase] || phaseRank.late);
      if (phaseCmp !== 0) {
        return phaseCmp;
      }
      if (a.order !== b.order) {
        return a.order - b.order;
      }
      return a.componentName.localeCompare(b.componentName);
    });
};

const registerRuntimeComponent = async (definition) => {
  const moduleContext = {
    module: 'app-init',
    runtimeComponent: definition.componentName,
  };

  const scriptUrl = (() => {
    try {
      return new URL(definition.script, document.baseURI).href;
    } catch {
      return '';
    }
  })();

  if (!scriptUrl) {
    warnOnce('UI_COMPONENT_INVALID', `Invalid runtime.component script URL for "${definition.componentName}"`, moduleContext);
    return;
  }

  try {
    const loaded = await import(scriptUrl);
    const exportName = definition.exportName || 'default';
    const init = loaded?.[exportName];
    if (typeof init !== 'function') {
      warnOnce(
        'UI_COMPONENT_INVALID',
        `runtime.component "${definition.componentName}" export "${exportName}" is not a function`,
        moduleContext
      );
      return;
    }

    const componentOptions = {};
    if (definition.scope !== '') {
      componentOptions.scope = definition.scope;
    }
    if (definition.selector !== '') {
      componentOptions.selector = definition.selector;
    }
    if (definition.configPath !== '') {
      componentOptions.configPath = definition.configPath;
    }

    runtime.register(definition.componentName, init, componentOptions);
  } catch (error) {
    warnOnce('UI_COMPONENT_IMPORT_FAILED', `Failed to import runtime.component "${definition.componentName}"`, {
      ...moduleContext,
      error,
    });
  }
};

const mountModuleComponentsByPhase = async (phase) => {
  const pageConfig = runtime.getPageConfig();
  const runtimeComponents = normalizeModuleRuntimeComponents(pageConfig?.moduleRuntimeComponents);
  const phaseComponents = runtimeComponents.filter((item) => item.phase === phase);
  for (const definition of phaseComponents) {
    // eslint-disable-next-line no-await-in-loop
    await registerRuntimeComponent(definition);
  }
};

const bootRuntime = async () => {
  // Phase A: low risk and global utilities.
  runtime.register('confirm-actions', initConfirmActions, {
    scope: 'global',
    configPath: 'components.confirmActions',
  });
  runtime.register('flash-auto-dismiss', initFlashAutoDismiss, {
    selector: '[data-app-component="flash-auto-dismiss"]',
    configPath: 'components.flashAutoDismiss',
    defaultConfig: {
      selector: '.notice[data-flash-timeout]',
    },
  });
  runtime.register('password-hints', initPasswordHints, {
    scope: 'global',
    configPath: 'components.passwordHints',
  });
  runtime.register('copy-badge', initBadgeCopy, {
    scope: 'global',
    configPath: 'components.copyBadge',
  });
  runtime.register('copy-field', initCopyField, {
    scope: 'global',
    configPath: 'components.copyField',
  });
  runtime.register('multiselect', initMultiSelectComponent, {
    scope: 'global',
    configPath: 'components.multiSelect',
  });
  runtime.register('token-select', initTokenSelect, {
    selector: '[data-app-component="token-select"]',
    configPath: 'components.tokenSelect',
  });
  runtime.register('details-state', initDetailsState, {
    scope: 'global',
    configPath: 'components.detailsState',
  });
  runtime.register('settings-telemetry', initTelemetrySettings, {
    scope: 'global',
    configPath: 'components.settingsTelemetry',
  });
  runtime.register('settings-audit', initSettingsAudit, {
    scope: 'global',
    configPath: 'components.settingsAudit',
  });
  runtime.register('auto-submit', initAutoSubmit, {
    scope: 'global',
    configPath: 'components.autoSubmit',
  });
  runtime.register('file-upload', initFileUpload, {
    selector: '[data-app-component="file-upload"]',
    configPath: 'components.fileUpload',
  });
  runtime.register('lookup-field', initLookupFields, {
    scope: 'global',
    configPath: 'components.lookupField',
    defaultConfig: {
      selector: '[data-app-lookup]',
    },
  });
  await mountModuleComponentsByPhase('early');

  // Phase B: structure-defining components.
  runtime.register('sidebar-toggle', initSidebarToggle, {
    scope: 'global',
    configPath: 'components.sidebarToggle',
  });
  runtime.register('aside-panels', initAsidePanels, {
    scope: 'global',
    configPath: 'components.asidePanels',
  });
  runtime.register('details-aside-toggle', initDetailsAsideToggle, {
    scope: 'global',
    configPath: 'components.detailsAsideToggle',
  });
  runtime.register('theme-controls', initThemeControls, {
    selector: '[data-app-component="theme-controls"]',
    configPath: 'components.themeControls',
  });
  runtime.register('contrast-toggle', initContrastToggle, {
    selector: '[data-app-component="contrast-toggle"]',
    configPath: 'components.contrastToggle',
  });
  runtime.register('tenant-switcher', initTenantSwitcher, {
    selector: '[data-app-component="tenant-switcher"]',
    configPath: 'components.tenantSwitcher',
  });
  runtime.register('custom-field-options-toggle', initCustomFieldOptionsToggle, {
    scope: 'global',
    configPath: 'components.customFieldOptionsToggle',
  });
  runtime.register('tenant-sso-toggle', initTenantSsoToggle, {
    scope: 'global',
    configPath: 'components.tenantSsoToggle',
  });
  runtime.register('tenant-ldap-toggle', initTenantLdapToggle, {
    scope: 'global',
    configPath: 'components.tenantLdapToggle',
  });
  runtime.register('standard-detail-page', initStandardDetailPages, {
    scope: 'global',
    configPath: 'components.standardDetailPage',
  });
  await mountModuleComponentsByPhase('default');

  // Phase C: high-risk (search, side panel interactions).
  runtime.register('global-search', initGlobalSearch, {
    selector: '[data-app-search-dialog]',
    configPath: 'components.globalSearch',
  });

  runtime.register('tabs', initTabs, {
    selector: '[data-app-component="tabs"]',
    configPath: 'components.tabs',
    defaultConfig: {
      selector: '[data-app-component="tabs"]',
      storageNamespace: 'app-ui',
      storageVersion: 'v1',
    },
  });
  runtime.register('list-tabs', initListTabs, {
    selector: '.app-list-tabs',
    configPath: 'components.listTabs',
    defaultConfig: {
      selector: '.app-list-tabs',
    },
  });
  runtime.register('session-warning', initSessionWarning, {
    selector: '[data-app-component="session-warning"]',
    configPath: 'components.sessionWarning',
    defaultConfig: {
      selector: '[data-app-session-warning-dialog]',
      enabled: true,
    },
  });
  runtime.register('fslightbox-refresh', initFsLightboxRefresh, {
    scope: 'global',
    configPath: 'components.fslightboxRefresh',
  });
  await mountModuleComponentsByPhase('late');

  runtime.mountAll();
};

void bootRuntime();
