import {
  DeesElement,
  type TemplateResult,
  property,
  customElement,
  html,
  css,
  cssManager,
  state,
} from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools';
import * as interfaces from '../../interfaces/index.js';
import type { DeesAppuiBar } from '../dees-appui-appbar/index.js';
import type { DeesAppuiMainmenu } from '../dees-appui-mainmenu/dees-appui-mainmenu.js';
import type { DeesAppuiSecondarymenu } from '../dees-appui-secondarymenu/dees-appui-secondarymenu.js';
import type { DeesAppuiMaincontent } from '../dees-appui-maincontent/dees-appui-maincontent.js';
import type { DeesAppuiActivitylog } from '../dees-appui-activitylog/dees-appui-activitylog.js';
import type { DeesAppuiBottombar } from '../dees-appui-bottombar/dees-appui-bottombar.js';
import { demoFunc } from './dees-appui.demo.js';
import { themeDefaultStyles } from '../../00theme.js';

// View registry for managing views
import { ViewRegistry } from './view.registry.js';

// Import child components
import '../dees-appui-appbar/index.js';
import '../dees-appui-bottombar/dees-appui-bottombar.js';
import '../dees-appui-mainmenu/dees-appui-mainmenu.js';
import '../dees-appui-secondarymenu/dees-appui-secondarymenu.js';
import '../dees-appui-maincontent/dees-appui-maincontent.js';
import '../dees-appui-activitylog/dees-appui-activitylog.js';

declare global {
  interface HTMLElementTagNameMap {
    'dees-appui': DeesAppui;
  }
}

@customElement('dees-appui')
export class DeesAppui extends DeesElement {
  public static demo = demoFunc;
  public static demoGroup = 'App UI';

  // ==========================================
  // REACTIVE OBSERVABLES (RxJS Subjects)
  // ==========================================

  /** Observable stream of view lifecycle events */
  public viewLifecycle$ = new domtools.plugins.smartrx.rxjs.Subject<interfaces.IViewLifecycleEvent>();

  /** Observable stream of view change events */
  public viewChanged$ = new domtools.plugins.smartrx.rxjs.Subject<interfaces.IViewChangeEvent>();

  // ==========================================
  // INTERNAL PROPERTIES (Properties for child components)
  // ==========================================

  // Properties for appbar
  @property({ type: Array })
  accessor appbarMenuItems: interfaces.IAppBarMenuItem[] = [];

  @property({ type: String })
  accessor appbarBreadcrumbs: string = '';

  @property({ type: String })
  accessor appbarBreadcrumbSeparator: string = ' > ';

  @property({ type: Boolean })
  accessor appbarShowWindowControls: boolean = true;

  @property({ type: Object })
  accessor appbarUser: interfaces.IAppUser | undefined = undefined;

  @property({ type: Array })
  accessor appbarProfileMenuItems: interfaces.IAppBarMenuItem[] = [];

  @property({ type: Boolean })
  accessor appbarShowSearch: boolean = false;

  // Properties for mainmenu
  @property({ type: String })
  accessor mainmenuLogoIcon: string = '';

  @property({ type: String })
  accessor mainmenuLogoText: string = '';

  @property({ type: Array })
  accessor mainmenuGroups: interfaces.IMenuGroup[] = [];

  @property({ type: Array })
  accessor mainmenuBottomTabs: interfaces.IMenuItem[] = [];

  @property({ type: Array })
  accessor mainmenuTabs: interfaces.IMenuItem[] = [];

  @property({ type: Object })
  accessor mainmenuSelectedTab: interfaces.IMenuItem | undefined = undefined;

  // Properties for secondarymenu
  @property({ type: String })
  accessor secondarymenuHeading: string = '';

  @property({ type: Array })
  accessor secondarymenuGroups: interfaces.ISecondaryMenuGroup[] = [];

  @property({ type: Object })
  accessor secondarymenuSelectedItem: interfaces.ISecondaryMenuItemTab | undefined = undefined;

  // Collapse states
  @property({ type: Boolean })
  accessor mainmenuCollapsed: boolean = false;

  @property({ type: Boolean })
  accessor secondarymenuCollapsed: boolean = false;

  // Visibility states
  @property({ type: Boolean })
  accessor mainmenuVisible: boolean = true;

  @property({ type: Boolean })
  accessor secondarymenuVisible: boolean = true;

  @property({ type: Boolean })
  accessor maincontentTabsVisible: boolean = true;

  @property({ type: Boolean })
  accessor contentTabsAutoHide: boolean = false;

  @property({ type: Number })
  accessor contentTabsAutoHideThreshold: number = 0;

  // Activity log visibility and count
  @state()
  accessor activityLogVisible: boolean = false;

  @state()
  accessor activityLogCount: number = 0;

  // Properties for maincontent
  @property({ type: Array })
  accessor maincontentTabs: interfaces.IMenuItem[] = [];

  @property({ type: Object })
  accessor maincontentSelectedTab: interfaces.IMenuItem | undefined = undefined;

  // References to child components
  @state()
  accessor appbar: DeesAppuiBar | undefined = undefined;

  @state()
  accessor mainmenu: DeesAppuiMainmenu | undefined = undefined;

  @state()
  accessor secondarymenu: DeesAppuiSecondarymenu | undefined = undefined;

  @state()
  accessor maincontent: DeesAppuiMaincontent | undefined = undefined;

  @state()
  accessor activitylogElement: DeesAppuiActivitylog | undefined = undefined;

  @state()
  accessor bottombarElement: DeesAppuiBottombar | undefined = undefined;

  @state()
  accessor bottombarVisible: boolean = true;

  // Current view state
  @state()
  accessor currentView: interfaces.IViewDefinition | undefined = undefined;

  // Internal services
  private viewRegistry: ViewRegistry = new ViewRegistry();
  private routerCleanup: (() => void) | null = null;
  private searchCallback: ((query: string) => void) | null = null;

  public static styles = [
    themeDefaultStyles,
    cssManager.defaultStyles,
    css`
      /* TODO: Migrate hardcoded values to --dees-* CSS variables */
      :host {
        position: absolute;
        height: 100%;
        width: 100%;
        background: ${cssManager.bdTheme('#f0f0f0', '#1a1a1a')};
      }
      .maingrid {
        position: absolute;
        top: 40px;
        height: calc(100% - 40px - 24px);
        width: 100%;
        display: grid;
        /* grid-template-columns set dynamically in template */
        grid-template-rows: 1fr;
        transition: grid-template-columns 0.3s ease, height 0.3s ease;
        overflow: hidden;
      }

      :host([bottombar-hidden]) .maingrid {
        height: calc(100% - 40px);
      }

      dees-appui-bottombar {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 4;
      }

      /* Z-index layering for proper stacking */
      .maingrid > dees-appui-mainmenu {
        position: relative;
        z-index: 3;
      }

      .maingrid > dees-appui-secondarymenu {
        position: relative;
        z-index: 2;
      }

      .maingrid > dees-appui-maincontent {
        position: relative;
        z-index: 1;
        min-height: 0;
      }

      .maingrid > dees-appui-activitylog {
        position: relative;
        z-index: 1;
        overflow: hidden;
        transition: opacity 0.3s ease, transform 0.3s ease;
      }

      .maingrid > dees-appui-activitylog.hidden {
        opacity: 0;
        transform: translateX(20px);
        pointer-events: none;
      }

      .maingrid > dees-appui-activitylog.visible {
        opacity: 1;
        transform: translateX(0);
      }

      /* View container for dynamically loaded views */
      .view-container {
        display: contents;
      }

      .view-container:empty {
        display: none;
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <dees-appui-appbar
        .menuItems=${this.appbarMenuItems}
        .breadcrumbs=${this.appbarBreadcrumbs}
        .breadcrumbSeparator=${this.appbarBreadcrumbSeparator}
        .showWindowControls=${this.appbarShowWindowControls}
        .user=${this.appbarUser}
        .profileMenuItems=${this.appbarProfileMenuItems}
        .showSearch=${this.appbarShowSearch}
        .showActivityLogToggle=${true}
        .activityLogCount=${this.activityLogCount}
        .activityLogActive=${this.activityLogVisible}
        @menu-select=${(e: CustomEvent) => this.handleAppbarMenuSelect(e)}
        @breadcrumb-navigate=${(e: CustomEvent) => this.handleAppbarBreadcrumbNavigate(e)}
        @search-click=${() => this.handleAppbarSearchClick()}
        @search-query=${(e: CustomEvent) => this.handleAppbarSearchQuery(e)}
        @user-menu-open=${() => this.handleAppbarUserMenuOpen()}
        @profile-menu-select=${(e: CustomEvent) => this.handleAppbarProfileMenuSelect(e)}
        @activity-toggle=${() => this.toggleActivityLog()}
      ></dees-appui-appbar>
      <div class="maingrid" style="grid-template-columns: auto auto 1fr ${this.activityLogVisible ? '280px' : '0px'};">
        ${this.mainmenuVisible ? html`
          <dees-appui-mainmenu
            .logoIcon=${this.mainmenuLogoIcon}
            .logoText=${this.mainmenuLogoText}
            .menuGroups=${this.mainmenuGroups}
            .bottomTabs=${this.mainmenuBottomTabs}
            .tabs=${this.mainmenuTabs}
            .selectedTab=${this.mainmenuSelectedTab}
            .collapsed=${this.mainmenuCollapsed}
            @tab-select=${(e: CustomEvent) => this.handleMainmenuTabSelect(e)}
            @collapse-change=${(e: CustomEvent) => this.handleMainmenuCollapseChange(e)}
          ></dees-appui-mainmenu>
        ` : ''}
        ${this.secondarymenuVisible ? html`
          <dees-appui-secondarymenu
            .heading=${this.secondarymenuHeading}
            .groups=${this.secondarymenuGroups}
            .selectedItem=${this.secondarymenuSelectedItem}
            .collapsed=${this.secondarymenuCollapsed}
            @item-select=${(e: CustomEvent) => this.handleSecondarymenuItemSelect(e)}
            @collapse-change=${(e: CustomEvent) => this.handleSecondarymenuCollapseChange(e)}
          ></dees-appui-secondarymenu>
        ` : ''}
        <dees-appui-maincontent
          .tabs=${this.maincontentTabs}
          .selectedTab=${this.maincontentSelectedTab}
          .showTabs=${this.maincontentTabsVisible}
          .tabsAutoHide=${this.contentTabsAutoHide}
          .tabsAutoHideThreshold=${this.contentTabsAutoHideThreshold}
          @tab-select=${(e: CustomEvent) => this.handleContentTabSelect(e)}
          @tab-close=${(e: CustomEvent) => this.handleContentTabClose(e)}
        >
          <div class="view-container"></div>
          <slot name="maincontent"></slot>
        </dees-appui-maincontent>
        <dees-appui-activitylog
          class="${this.activityLogVisible ? 'visible' : 'hidden'}"
        ></dees-appui-activitylog>
      </div>
      ${this.bottombarVisible ? html`
        <dees-appui-bottombar></dees-appui-bottombar>
      ` : ''}
    `;
  }

  async firstUpdated() {
    // Get references to child components
    this.appbar = this.shadowRoot!.querySelector('dees-appui-appbar') as DeesAppuiBar;
    this.mainmenu = this.shadowRoot!.querySelector('dees-appui-mainmenu') as DeesAppuiMainmenu;
    this.secondarymenu = this.shadowRoot!.querySelector('dees-appui-secondarymenu') as DeesAppuiSecondarymenu;
    this.maincontent = this.shadowRoot!.querySelector('dees-appui-maincontent') as DeesAppuiMaincontent;
    this.activitylogElement = this.shadowRoot!.querySelector('dees-appui-activitylog') as DeesAppuiActivitylog;
    this.bottombarElement = this.shadowRoot!.querySelector('dees-appui-bottombar') as DeesAppuiBottombar;

    // Subscribe to activity log entry changes for badge count
    if (this.activitylogElement) {
      this.activitylogElement.entries$.subscribe((entries) => {
        this.activityLogCount = entries.length;
      });
    }

    // Set appui reference in view registry for lifecycle context
    this.viewRegistry.setAppuiRef(this as unknown as interfaces.TDeesAppui);
  }

  async disconnectedCallback() {
    await super.disconnectedCallback();
    // Clean up router listener
    if (this.routerCleanup) {
      this.routerCleanup();
      this.routerCleanup = null;
    }
    // Complete subjects
    this.viewLifecycle$.complete();
    this.viewChanged$.complete();
  }

  // ==========================================
  // PROGRAMMATIC API: APP BAR
  // ==========================================

  /**
   * Set the app bar menu items (File, Edit, View, etc.)
   */
  public setAppBarMenus(menus: interfaces.IAppBarMenuItem[]): void {
    this.appbarMenuItems = [...menus];
  }

  /**
   * Update a single app bar menu by name
   */
  public updateAppBarMenu(name: string, update: Partial<interfaces.IAppBarMenuItem>): void {
    this.appbarMenuItems = this.appbarMenuItems.map(menu => {
      // Check if it's not a divider and has a name property
      if ('name' in menu && menu.name === name) {
        return { ...menu, ...update };
      }
      return menu;
    });
  }

  /**
   * Set the breadcrumbs (string or array)
   */
  public setBreadcrumbs(breadcrumbs: string | string[]): void {
    if (Array.isArray(breadcrumbs)) {
      this.appbarBreadcrumbs = breadcrumbs.join(this.appbarBreadcrumbSeparator);
    } else {
      this.appbarBreadcrumbs = breadcrumbs;
    }
  }

  /**
   * Set the current user
   */
  public setUser(user: interfaces.IAppUser | undefined): void {
    this.appbarUser = user;
  }

  /**
   * Set the profile dropdown menu items
   */
  public setProfileMenuItems(items: interfaces.IAppBarMenuItem[]): void {
    this.appbarProfileMenuItems = [...items];
  }

  /**
   * Set search bar visibility
   */
  public setSearchVisible(visible: boolean): void {
    this.appbarShowSearch = visible;
  }

  /**
   * Set window controls visibility
   */
  public setWindowControlsVisible(visible: boolean): void {
    this.appbarShowWindowControls = visible;
  }

  /**
   * Register a search callback
   */
  public onSearch(callback: (query: string) => void): void {
    this.searchCallback = callback;
  }

  // ==========================================
  // PROGRAMMATIC API: MAIN MENU
  // ==========================================

  /**
   * Set the entire main menu configuration
   */
  public setMainMenu(config: interfaces.IMainMenuConfig): void {
    if (config.logoIcon !== undefined) {
      this.mainmenuLogoIcon = config.logoIcon;
    }
    if (config.logoText !== undefined) {
      this.mainmenuLogoText = config.logoText;
    }
    if (config.groups !== undefined) {
      this.mainmenuGroups = [...config.groups];
    }
    if (config.bottomTabs !== undefined) {
      this.mainmenuBottomTabs = [...config.bottomTabs];
    }
  }

  /**
   * Update a specific menu group by name
   */
  public updateMainMenuGroup(groupName: string, update: Partial<interfaces.IMenuGroup>): void {
    this.mainmenuGroups = this.mainmenuGroups.map(group =>
      group.name === groupName ? { ...group, ...update } : group
    );
  }

  /**
   * Add a menu item to a specific group
   */
  public addMainMenuItem(groupName: string, tab: interfaces.IMenuItem): void {
    this.mainmenuGroups = this.mainmenuGroups.map(group => {
      if (group.name === groupName) {
        return {
          ...group,
          items: [...(group.items || []), tab],
        };
      }
      return group;
    });
  }

  /**
   * Remove a menu item from a group by key
   */
  public removeMainMenuItem(groupName: string, tabKey: string): void {
    this.mainmenuGroups = this.mainmenuGroups.map(group => {
      if (group.name === groupName) {
        return {
          ...group,
          items: (group.items || []).filter(t => t.key !== tabKey),
        };
      }
      return group;
    });
  }

  /**
   * Set the selected main menu item by key
   */
  public setMainMenuSelection(tabKey: string): void {
    for (const group of this.mainmenuGroups) {
      const tab = group.items?.find(t => t.key === tabKey);
      if (tab) {
        this.mainmenuSelectedTab = tab;
        return;
      }
    }
    // Check bottom tabs
    const bottomTab = this.mainmenuBottomTabs.find(t => t.key === tabKey);
    if (bottomTab) {
      this.mainmenuSelectedTab = bottomTab;
    }
  }

  /**
   * Set main menu collapsed state
   */
  public setMainMenuCollapsed(collapsed: boolean): void {
    this.mainmenuCollapsed = collapsed;
  }

  /**
   * Set main menu visibility
   */
  public setMainMenuVisible(visible: boolean): void {
    this.mainmenuVisible = visible;
  }

  /**
   * Set secondary menu collapsed state
   */
  public setSecondaryMenuCollapsed(collapsed: boolean): void {
    this.secondarymenuCollapsed = collapsed;
  }

  /**
   * Set secondary menu visibility
   */
  public setSecondaryMenuVisible(visible: boolean): void {
    this.secondarymenuVisible = visible;
  }

  /**
   * Set content tabs visibility
   */
  public setContentTabsVisible(visible: boolean): void {
    this.maincontentTabsVisible = visible;
  }

  /**
   * Set content tabs auto-hide behavior
   * @param enabled - Enable auto-hide feature
   * @param threshold - Hide when tabs.length <= threshold (default 0 = hide when no tabs)
   */
  public setContentTabsAutoHide(enabled: boolean, threshold: number = 0): void {
    this.contentTabsAutoHide = enabled;
    this.contentTabsAutoHideThreshold = threshold;
  }

  /**
   * Set a badge on a main menu item
   */
  public setMainMenuBadge(tabKey: string, badge: string | number): void {
    this.mainmenuGroups = this.mainmenuGroups.map(group => ({
      ...group,
      items: (group.items || []).map(tab =>
        tab.key === tabKey ? { ...tab, badge } : tab
      ),
    }));
    // Also check bottom tabs
    this.mainmenuBottomTabs = this.mainmenuBottomTabs.map(tab =>
      tab.key === tabKey ? { ...tab, badge } : tab
    );
  }

  /**
   * Clear a badge from a main menu item
   */
  public clearMainMenuBadge(tabKey: string): void {
    this.mainmenuGroups = this.mainmenuGroups.map(group => ({
      ...group,
      items: (group.items || []).map(tab => {
        if (tab.key === tabKey) {
          const { badge, ...rest } = tab;
          return rest;
        }
        return tab;
      }),
    }));
    // Also check bottom tabs
    this.mainmenuBottomTabs = this.mainmenuBottomTabs.map(tab => {
      if (tab.key === tabKey) {
        const { badge, ...rest } = tab;
        return rest;
      }
      return tab;
    });
  }

  // ==========================================
  // PROGRAMMATIC API: SECONDARY MENU
  // ==========================================

  /**
   * Set the secondary menu configuration
   */
  public setSecondaryMenu(config: { heading?: string; groups: interfaces.ISecondaryMenuGroup[] }): void {
    if (config.heading !== undefined) {
      this.secondarymenuHeading = config.heading;
    }
    this.secondarymenuGroups = [...config.groups];
  }

  /**
   * Update a specific secondary menu group
   */
  public updateSecondaryMenuGroup(groupName: string, update: Partial<interfaces.ISecondaryMenuGroup>): void {
    this.secondarymenuGroups = this.secondarymenuGroups.map(group =>
      group.name === groupName ? { ...group, ...update } : group
    );
  }

  /**
   * Add an item to a secondary menu group
   */
  public addSecondaryMenuItem(
    groupName: string,
    item: interfaces.ISecondaryMenuItem
  ): void {
    this.secondarymenuGroups = this.secondarymenuGroups.map(group => {
      if (group.name === groupName) {
        return {
          ...group,
          items: [...group.items, item],
        };
      }
      return group;
    });
  }

  /**
   * Set the selected secondary menu item by key (for tab items only)
   */
  public setSecondaryMenuSelection(itemKey: string): void {
    for (const group of this.secondarymenuGroups) {
      const item = group.items.find(i => 'key' in i && i.key === itemKey);
      if (item && (!('type' in item) || item.type === 'tab' || item.type === undefined)) {
        this.secondarymenuSelectedItem = item as interfaces.ISecondaryMenuItemTab;
        return;
      }
    }
  }

  /**
   * Clear the secondary menu
   */
  public clearSecondaryMenu(): void {
    this.secondarymenuHeading = '';
    this.secondarymenuGroups = [];
    this.secondarymenuSelectedItem = undefined;
  }

  // ==========================================
  // PROGRAMMATIC API: CONTENT TABS
  // ==========================================

  /**
   * Set the content tabs
   */
  public setContentTabs(tabs: interfaces.IMenuItem[]): void {
    this.maincontentTabs = [...tabs];
    if (tabs.length > 0 && !this.maincontentSelectedTab) {
      this.maincontentSelectedTab = tabs[0];
    }
  }

  /**
   * Add a content tab
   */
  public addContentTab(tab: interfaces.IMenuItem): void {
    this.maincontentTabs = [...this.maincontentTabs, tab];
  }

  /**
   * Remove a content tab by key
   */
  public removeContentTab(tabKey: string): void {
    this.maincontentTabs = this.maincontentTabs.filter(t => t.key !== tabKey);
    if (this.maincontentSelectedTab?.key === tabKey) {
      this.maincontentSelectedTab = this.maincontentTabs[0];
    }
  }

  /**
   * Select a content tab by key
   */
  public selectContentTab(tabKey: string): void {
    const tab = this.maincontentTabs.find(t => t.key === tabKey);
    if (tab) {
      this.maincontentSelectedTab = tab;
    }
  }

  /**
   * Get the currently selected content tab
   */
  public getSelectedContentTab(): interfaces.IMenuItem | undefined {
    return this.maincontentSelectedTab;
  }

  // ==========================================
  // PROGRAMMATIC API: ACTIVITY LOG
  // ==========================================

  /**
   * Get the activity log API
   */
  public get activityLog(): interfaces.IActivityLogAPI {
    if (!this.activitylogElement) {
      // Return a deferred API that will work after firstUpdated
      return {
        add: (entry) => {
          this.updateComplete.then(() => this.activitylogElement?.add(entry));
        },
        addMany: (entries) => {
          this.updateComplete.then(() => this.activitylogElement?.addMany(entries));
        },
        clear: () => {
          this.updateComplete.then(() => this.activitylogElement?.clear());
        },
        getEntries: () => this.activitylogElement?.getEntries() || [],
        filter: (criteria) => this.activitylogElement?.filter(criteria) || [],
        search: (query) => this.activitylogElement?.search(query) || [],
      };
    }
    return {
      add: (entry) => this.activitylogElement!.add(entry),
      addMany: (entries) => this.activitylogElement!.addMany(entries),
      clear: () => this.activitylogElement!.clear(),
      getEntries: () => this.activitylogElement!.getEntries(),
      filter: (criteria) => this.activitylogElement!.filter(criteria),
      search: (query) => this.activitylogElement!.search(query),
    };
  }

  /**
   * Set activity log visibility
   */
  public setActivityLogVisible(visible: boolean): void {
    this.activityLogVisible = visible;
  }

  /**
   * Toggle activity log visibility
   */
  public toggleActivityLog(): void {
    this.activityLogVisible = !this.activityLogVisible;
  }

  /**
   * Get activity log visibility state
   */
  public getActivityLogVisible(): boolean {
    return this.activityLogVisible;
  }

  // ==========================================
  // PROGRAMMATIC API: BOTTOM BAR
  // ==========================================

  /**
   * Get the bottom bar API for widget/action management
   */
  public get bottomBar(): interfaces.IBottomBarAPI {
    if (!this.bottombarElement) {
      // Return a deferred API that will work after firstUpdated
      return {
        addWidget: (widget) => {
          this.updateComplete.then(() => this.bottombarElement?.addWidget(widget));
        },
        updateWidget: (id, update) => {
          this.updateComplete.then(() => this.bottombarElement?.updateWidget(id, update));
        },
        removeWidget: (id) => {
          this.updateComplete.then(() => this.bottombarElement?.removeWidget(id));
        },
        getWidget: (id) => this.bottombarElement?.getWidget(id),
        clearWidgets: () => {
          this.updateComplete.then(() => this.bottombarElement?.clearWidgets());
        },
        addAction: (action) => {
          this.updateComplete.then(() => this.bottombarElement?.addAction(action));
        },
        removeAction: (id) => {
          this.updateComplete.then(() => this.bottombarElement?.removeAction(id));
        },
        clearActions: () => {
          this.updateComplete.then(() => this.bottombarElement?.clearActions());
        },
      };
    }
    return {
      addWidget: (widget) => this.bottombarElement!.addWidget(widget),
      updateWidget: (id, update) => this.bottombarElement!.updateWidget(id, update),
      removeWidget: (id) => this.bottombarElement!.removeWidget(id),
      getWidget: (id) => this.bottombarElement!.getWidget(id),
      clearWidgets: () => this.bottombarElement!.clearWidgets(),
      addAction: (action) => this.bottombarElement!.addAction(action),
      removeAction: (id) => this.bottombarElement!.removeAction(id),
      clearActions: () => this.bottombarElement!.clearActions(),
    };
  }

  /**
   * Set bottom bar visibility
   */
  public setBottomBarVisible(visible: boolean): void {
    this.bottombarVisible = visible;
    if (!visible) {
      this.setAttribute('bottombar-hidden', '');
    } else {
      this.removeAttribute('bottombar-hidden');
    }
  }

  /**
   * Get bottom bar visibility state
   */
  public getBottomBarVisible(): boolean {
    return this.bottombarVisible;
  }

  // ==========================================
  // PROGRAMMATIC API: NAVIGATION
  // ==========================================

  /**
   * Navigate to a view by ID
   */
  public async navigateToView(viewId: string, params?: Record<string, string>): Promise<boolean> {
    const view = this.viewRegistry.get(viewId);
    if (!view) {
      console.warn(`Cannot navigate to unknown view: ${viewId}`);
      return false;
    }

    // Check if current view allows navigation
    const canLeave = await this.viewRegistry.canLeaveCurrentView();
    if (canLeave !== true) {
      if (typeof canLeave === 'string') {
        // Show confirmation dialog
        const confirmed = window.confirm(canLeave);
        if (!confirmed) return false;
      } else {
        return false;
      }
    }

    // Emit loading event
    this.viewLifecycle$.next({ type: 'loading', viewId });

    try {
      await this.loadView(view, params);

      // Update URL hash
      const route = view.route || viewId;
      const newHash = `#${route}`;
      if (window.location.hash !== newHash) {
        window.history.pushState({ viewId }, '', newHash);
      }

      return true;
    } catch (error) {
      this.viewLifecycle$.next({ type: 'loadError', viewId, error });
      return false;
    }
  }

  /**
   * Get the current view
   */
  public getCurrentView(): interfaces.IViewDefinition | undefined {
    return this.currentView;
  }

  /**
   * Get access to the view registry (for advanced use)
   */
  public getViewRegistry(): ViewRegistry {
    return this.viewRegistry;
  }

  // ==========================================
  // UNIFIED CONFIGURATION
  // ==========================================

  /**
   * Configure the app shell with a unified config object
   */
  public configure(config: interfaces.IAppConfig): void {
    // Register views
    if (config.views) {
      this.viewRegistry.clear();
      this.viewRegistry.registerAll(config.views);
    }

    // Apply branding
    if (config.branding) {
      this.mainmenuLogoIcon = config.branding.logoIcon || '';
      this.mainmenuLogoText = config.branding.logoText || '';
    }

    // Apply app bar config
    if (config.appBar) {
      this.appbarMenuItems = config.appBar.menuItems || [];
      this.appbarBreadcrumbs = config.appBar.breadcrumbs || '';
      this.appbarBreadcrumbSeparator = config.appBar.breadcrumbSeparator || ' > ';
      this.appbarShowWindowControls = config.appBar.showWindowControls ?? true;
      this.appbarShowSearch = config.appBar.showSearch ?? false;
      this.appbarUser = config.appBar.user;
      this.appbarProfileMenuItems = config.appBar.profileMenuItems || [];
    }

    // Build main menu from view references or direct config
    if (config.mainMenu) {
      if (config.mainMenu.sections) {
        this.mainmenuGroups = this.buildMainMenuFromSections(config);
      } else if (config.mainMenu.groups) {
        this.mainmenuGroups = config.mainMenu.groups;
      }

      if (config.mainMenu.logoIcon) {
        this.mainmenuLogoIcon = config.mainMenu.logoIcon;
      }
      if (config.mainMenu.logoText) {
        this.mainmenuLogoText = config.mainMenu.logoText;
      }
      if (config.mainMenu.bottomTabs) {
        this.mainmenuBottomTabs = config.mainMenu.bottomTabs;
      } else if (config.mainMenu.bottomItems) {
        this.mainmenuBottomTabs = this.buildBottomTabsFromItems(config.mainMenu.bottomItems);
      }
    }

    // Apply bottom bar config
    if (config.bottomBar) {
      this.setBottomBarVisible(config.bottomBar.visible ?? true);

      if (config.bottomBar.widgets) {
        config.bottomBar.widgets.forEach(widget => {
          this.bottomBar.addWidget(widget);
        });
      }

      if (config.bottomBar.actions) {
        config.bottomBar.actions.forEach(action => {
          this.bottomBar.addAction(action);
        });
      }
    }

    // Setup domtools.router integration
    this.setupRouterIntegration(config);

    // Bind event callbacks
    if (config.onViewChange) {
      this.viewChanged$.subscribe((event) => {
        config.onViewChange!(event.viewId, event.view);
      });
    }

    if (config.onSearch) {
      this.searchCallback = config.onSearch;
    }

    // Navigate to default view
    if (config.defaultView) {
      this.navigateToView(config.defaultView);
    }
  }

  // ==========================================
  // PRIVATE HELPER METHODS
  // ==========================================

  private setupRouterIntegration(config: interfaces.IAppConfig): void {
    // Handle hash change events
    const handleHashChange = () => {
      const hash = window.location.hash.slice(1); // Remove #
      if (!hash) return;

      const match = this.viewRegistry.findByRoute(hash);
      if (match) {
        this.navigateToView(match.view.id, match.params);
      }
    };

    window.addEventListener('hashchange', handleHashChange);

    // Store cleanup function
    this.routerCleanup = () => {
      window.removeEventListener('hashchange', handleHashChange);
    };

    // Handle initial route from hash
    const currentHash = window.location.hash.slice(1);
    if (currentHash) {
      const match = this.viewRegistry.findByRoute(currentHash);
      if (match) {
        // Use setTimeout to allow component to fully initialize
        setTimeout(() => this.navigateToView(match.view.id, match.params), 0);
      }
    }
  }

  private buildMainMenuFromSections(config: interfaces.IAppConfig): interfaces.IMenuGroup[] {
    if (!config.mainMenu?.sections) return [];

    return config.mainMenu.sections.map((section) => ({
      name: section.name,
      items: section.views
        .map((viewId) => {
          const view = this.viewRegistry.get(viewId);
          if (!view) {
            console.warn(`View "${viewId}" not found in registry`);
            return null;
          }
          return {
            key: view.id,
            iconName: view.iconName,
            action: () => this.navigateToView(viewId),
            badge: view.badge,
          } as interfaces.IMenuItem;
        })
        .filter(Boolean) as interfaces.IMenuItem[],
    }));
  }

  private buildBottomTabsFromItems(items: string[]): interfaces.IMenuItem[] {
    return items
      .map((viewId) => {
        const view = this.viewRegistry.get(viewId);
        if (!view) {
          console.warn(`View "${viewId}" not found in registry`);
          return null;
        }
        return {
          key: view.id,
          iconName: view.iconName,
          action: () => this.navigateToView(viewId),
        } as interfaces.IMenuItem;
      })
      .filter(Boolean) as interfaces.IMenuItem[];
  }

  private async loadView(
    view: interfaces.IViewDefinition,
    params?: Record<string, string>
  ): Promise<void> {
    const previousView = this.currentView;
    this.currentView = view;

    // Get view container
    const viewContainer = this.maincontent?.querySelector('.view-container')
      || this.shadowRoot?.querySelector('.view-container');

    if (viewContainer) {
      // Activate view with caching and lifecycle hooks
      const element = await this.viewRegistry.activateView(
        view.id,
        viewContainer as HTMLElement,
        params
      );

      if (element) {
        // Emit lifecycle event
        this.viewLifecycle$.next({
          type: 'activated',
          viewId: view.id,
          element,
          params,
        });
      }
    }

    // Apply view-specific secondary menu
    if (view.secondaryMenu) {
      this.secondarymenuGroups = view.secondaryMenu;
      this.secondarymenuHeading = view.name;
    }

    // Apply view-specific content tabs
    if (view.contentTabs) {
      this.maincontentTabs = view.contentTabs;
    }

    // Update main menu selection
    this.setMainMenuSelection(view.id);

    // Emit view change event
    const changeEvent: interfaces.IViewChangeEvent = {
      viewId: view.id,
      view,
      previousView,
      params,
    };
    this.viewChanged$.next(changeEvent);

    // Also dispatch DOM event for backwards compatibility
    this.dispatchEvent(
      new CustomEvent('view-change', {
        detail: changeEvent,
        bubbles: true,
        composed: true,
      })
    );
  }

  // ==========================================
  // EVENT HANDLERS (Internal)
  // ==========================================

  private handleAppbarMenuSelect(e: CustomEvent) {
    this.dispatchEvent(new CustomEvent('appbar-menu-select', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleAppbarBreadcrumbNavigate(e: CustomEvent) {
    this.dispatchEvent(new CustomEvent('appbar-breadcrumb-navigate', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleAppbarSearchClick() {
    this.dispatchEvent(new CustomEvent('appbar-search-click', {
      bubbles: true,
      composed: true
    }));
  }

  private handleAppbarSearchQuery(e: CustomEvent) {
    if (this.searchCallback) {
      this.searchCallback(e.detail.query);
    }
    this.dispatchEvent(new CustomEvent('search-query', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleAppbarUserMenuOpen() {
    this.dispatchEvent(new CustomEvent('appbar-user-menu-open', {
      bubbles: true,
      composed: true
    }));
  }

  private handleAppbarProfileMenuSelect(e: CustomEvent) {
    this.dispatchEvent(new CustomEvent('appbar-profile-menu-select', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleMainmenuTabSelect(e: CustomEvent) {
    this.mainmenuSelectedTab = e.detail.tab;
    this.dispatchEvent(new CustomEvent('mainmenu-tab-select', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleSecondarymenuItemSelect(e: CustomEvent) {
    this.secondarymenuSelectedItem = e.detail.item;
    this.dispatchEvent(new CustomEvent('secondarymenu-item-select', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleMainmenuCollapseChange(e: CustomEvent) {
    this.mainmenuCollapsed = e.detail.collapsed;
    this.dispatchEvent(new CustomEvent('mainmenu-collapse-change', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleSecondarymenuCollapseChange(e: CustomEvent) {
    this.secondarymenuCollapsed = e.detail.collapsed;
    this.dispatchEvent(new CustomEvent('secondarymenu-collapse-change', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleContentTabSelect(e: CustomEvent) {
    this.maincontentSelectedTab = e.detail.tab;
    this.dispatchEvent(new CustomEvent('content-tab-select', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }

  private handleContentTabClose(e: CustomEvent) {
    this.dispatchEvent(new CustomEvent('content-tab-close', {
      detail: e.detail,
      bubbles: true,
      composed: true
    }));
  }
}
