import { Component, EventEmitter, HostListener, Input, Output, inject, effect, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UiModeService } from '../../shared/services/ui-mode.service';
import { ResponsiveService } from '../../shared/services/responsive.service';
import { MobileNavService } from '../../shared/services/mobile-nav.service';
import { FileExplorerComponent } from '../../../components/file-explorer/file-explorer.component';
import { NoteViewerComponent } from '../../../components/tags-view/note-viewer/note-viewer.component';
import { VaultService } from '../../../services/vault.service';
import type { VaultNode, Note, TagInfo } from '../../../types';
import { AppBottomNavigationComponent } from '../../features/bottom-nav/app-bottom-navigation.component';
import { AppSidebarDrawerComponent } from '../../features/sidebar/app-sidebar-drawer.component';
import { AppTocOverlayComponent } from '../../features/note-view/app-toc-overlay.component';
import { SwipeNavDirective } from '../../shared/directives/swipe-nav.directive';
import { PaginatedNotesListComponent } from '../../features/list/paginated-notes-list.component';
import { NimbusSidebarComponent } from '../../features/sidebar/nimbus-sidebar.component';
import { QuickLinksComponent } from '../../features/quick-links/quick-links.component';
import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrollable-overlay.directive';
import { MarkdownPlaygroundComponent } from '../../features/tests/markdown-playground/markdown-playground.component';
import { TestsPanelComponent } from '../../features/tests/tests-panel.component';
import { TestExcalidrawPageComponent } from '../../features/tests/test-excalidraw-page.component';
import { ParametersPage } from '../../features/parameters/parameters.page';
import { AboutPanelComponent } from '../../features/about/about-panel.component';
import { UrlStateService } from '../../services/url-state.service';
import { FilterService } from '../../services/filter.service';
import { NoteInfoModalComponent } from '../../features/note-info/note-info-modal.component';
import { NoteInfoModalService } from '../../services/note-info-modal.service';
import { InPageSearchService } from '../../shared/search/in-page-search.service';
import { InPageSearchOverlayComponent } from '../../shared/search/in-page-search-overlay.component';
@Component({
  selector: 'app-shell-nimbus-layout',
  standalone: true,
  imports: [CommonModule, FileExplorerComponent, NoteViewerComponent, AppBottomNavigationComponent, AppSidebarDrawerComponent, AppTocOverlayComponent, SwipeNavDirective, PaginatedNotesListComponent, NimbusSidebarComponent, QuickLinksComponent, ScrollableOverlayDirective, MarkdownPlaygroundComponent, TestsPanelComponent, TestExcalidrawPageComponent, ParametersPage, AboutPanelComponent, NoteInfoModalComponent, InPageSearchOverlayComponent],
  template: `
    
      
      
      
      
        
        
          
        
        
          
          
          
            
              {{
                f === 'quick' ? 'Quick Links' :
                (f === 'folders' ? 'Folders' :
                (f === 'tags' ? 'Tags' :
                (f === 'trash' ? 'Trash' :
                (f === 'help' ? 'Help' :
                (f === 'about' ? 'About' :
                (f === 'tests' ? 'Tests' :
                (f === 'playground' ? 'Playground' : '')))))))
              }}
              
             
            
              
                
                
                
                  
                    - 
                      
                    
 
                  
                 
                
                   0; else emptyTrash">
                    
                    
                  
                  
                    La corbeille est vide
                  
                 
                
                  
                
                
                  
                
                
                  
                  
                  
                
                
                  
                
                Empty
              
             
           
        
        
        
        
        
        
        
        
        
       
      
      
      
      
        
        @if (mobileNav.activeTab() === 'list') {
          
        }
        @if (mobileNav.activeTab() === 'page') {
          @if (activeView === 'parameters') {
            
          } @else if (activeView === 'markdown-playground') {
            
          } @else if (activeView === 'tests-panel') {
            
          } @else if (activeView === 'tests-excalidraw') {
            
          } @else {
            
              @if (selectedNote) {
                
              } @else {
                
                  📄
                  Aucune page sélectionnée pour le moment.
                 
              }
            
          }
        }
        
        
       
      
      
      
      
     
  `
})
export class AppShellNimbusLayoutComponent implements AfterViewInit {
  ui = inject(UiModeService);
  vault = inject(VaultService);
  responsive = inject(ResponsiveService);
  mobileNav = inject(MobileNavService);
  urlState = inject(UrlStateService);
  filters = inject(FilterService);
  noteInfo = inject(NoteInfoModalService);
  inPageSearch = inject(InPageSearchService);
  noteFullScreen = false;
  showAboutPanel = false;
  @Input() vaultName = '';
  @Input() effectiveFileTree: VaultNode[] = [];
  @Input() selectedNoteId: string | null = '';
  @Input() selectedNote: Note | undefined;
  @Input() renderedNoteContent = '';
  @Input() tableOfContents: Array<{ level: number; text: string; id: string }> = [];
  @Input() isSidebarOpen = true;
  @Input() isOutlineOpen = false;
  @Input() leftSidebarWidth = 288;
  @Input() rightSidebarWidth = 288;
  @Input() searchTerm = '';
  @Input() centerPanelWidth = 384;
  @Input() tags: TagInfo[] = [];
  @Input() activeView: string = 'files';
  @ViewChild('pageRoot', { static: false }) pageRoot?: ElementRef;
  @Output() noteSelected = new EventEmitter();
  @Output() tagClicked = new EventEmitter();
  @Output() wikiLinkActivated = new EventEmitter();
  @Output() toggleSidebarRequest = new EventEmitter();
  @Output() toggleOutlineRequest = new EventEmitter();
  @Output() leftResizeStart = new EventEmitter();
  @Output() rightResizeStart = new EventEmitter();
  @Output() centerResizeStart = new EventEmitter();
  @Output() navigateHeading = new EventEmitter();
  @Output() searchTermChange = new EventEmitter();
  @Output() searchOptionsChange = new EventEmitter();
  @Output() noteCreated = new EventEmitter();
  @Output() noteCreatedAndSelected = new EventEmitter<{ id: string; filePath: string }>();
  @Output() markdownPlaygroundSelected = new EventEmitter();
  @Output() parametersOpened = new EventEmitter();
  @Output() helpPageRequested = new EventEmitter();
  @Output() testsPanelRequested = new EventEmitter();
  @Output() testsExcalidrawRequested = new EventEmitter();
  folderFilter: string | null = null;
  listQuery: string = '';
  hoveredFlyout: 'quick' | 'folders' | 'tags' | 'trash' | 'help' | 'about' | 'tests' | 'playground' | null = null;
  private flyoutCloseTimer: any = null;
  tagFilter: string | null = null;
  quickLinkFilter: 'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | null = null;
  private suppressNextNoteSelection = false;
  // --- URL State <-> Layout sync ---
  private mapUrlQuickToInternal(q: string | null): AppShellNimbusLayoutComponent['quickLinkFilter'] {
    switch ((q || '').toLowerCase()) {
      case 'favoris':
      case 'favorites':
        return 'favoris';
      case 'publié':
      case 'publie':
      case 'publish':
        return 'publish';
      case 'brouillons':
      case 'drafts':
      case 'draft':
        return 'draft';
      case 'modèles':
      case 'modeles':
      case 'templates':
      case 'template':
        return 'template';
      case 'tâches':
      case 'taches':
      case 'tasks':
      case 'task':
        return 'task';
      case 'privé':
      case 'prive':
      case 'private':
        return 'private';
      case 'archive':
        return 'archive';
      default:
        return null;
    }
  }
  private mapInternalQuickToUrl(id: AppShellNimbusLayoutComponent['quickLinkFilter']): string | null {
    switch (id) {
      case 'favoris': return 'Favoris';
      case 'publish': return 'Publié';
      case 'draft': return 'Brouillons';
      case 'template': return 'Modèles';
      case 'task': return 'Tâches';
      case 'private': return 'Privé';
      case 'archive': return 'Archive';
      default: return null;
    }
  }
  // React to URL state changes and align layout
  _urlEffect = effect(() => {
    const note = this.urlState.currentNote();
    const tag = this.urlState.activeTag();
    const folder = this.urlState.activeFolder();
    const quick = this.urlState.activeQuickLink();
    const search = this.urlState.activeSearch();
    console.log('🎨 Layout _urlEffect:', {note, tag, folder, quick, search});
    
    // Apply search query
    if (search !== null && this.listQuery !== (search || '')) {
      this.listQuery = search || '';
    }
    // If a note is specified, select it and focus page, but DO NOT early-return:
    // we still want to apply list filters (tag/folder/quick) from the URL so the list matches.
    const hasNote = !!note;
    if (hasNote) {
      if (this.selectedNoteId !== note!.id) {
        this.noteSelected.emit(note!.id);
      }
      // Ensure page view visible on small screens
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('page');
      }
      // Exit fullscreen if needed
      if (this.noteFullScreen) {
        this.noteFullScreen = false;
        document.body.classList.remove('note-fullscreen-active');
      }
    }
    // Otherwise, synchronize filters from URL
    if (tag !== null) {
      const norm = (tag || '').replace(/^#/, '').trim().toLowerCase();
      if (this.tagFilter !== norm) {
        this.tagFilter = norm || null;
        this.folderFilter = null;
        this.quickLinkFilter = null;
        if (!hasNote) this.autoSelectFirstNote();
        if (!this.responsive.isDesktop()) this.mobileNav.setActiveTab('list');
      }
      // Auto-open tags flyout when tag filter is active
      if (this.hoveredFlyout !== 'tags') {
        console.log('🎨 Layout - opening tags flyout for tag filter');
        this.openFlyout('tags');
      }
    } else if (folder !== null) {
      if (this.folderFilter !== (folder || null)) {
        this.folderFilter = folder || null;
        this.tagFilter = null;
        this.quickLinkFilter = null;
        if (!hasNote) this.autoSelectFirstNote();
        if (!this.responsive.isDesktop()) this.mobileNav.setActiveTab('list');
      }
      // Auto-open folders flyout when folder filter is active
      if (this.hoveredFlyout !== 'folders') {
        console.log('🎨 Layout - opening folders flyout for folder filter');
        this.openFlyout('folders');
      }
    } else if (quick !== null) {
      const internal = this.mapUrlQuickToInternal(quick);
      if (this.quickLinkFilter !== internal) {
        this.quickLinkFilter = internal;
        this.folderFilter = null;
        this.tagFilter = null;
        if (internal === 'favoris') {
          this.suppressNextNoteSelection = true;
        }
        if (!hasNote && !this.suppressNextNoteSelection) {
          this.autoSelectFirstNote();
        }
        if (!this.responsive.isDesktop()) {
          this.mobileNav.setActiveTab('list');
        }
      } else if (!hasNote && !this.suppressNextNoteSelection) {
        this.autoSelectFirstNote();
      }
      // Auto-open quick flyout when quick filter is active
      if (this.hoveredFlyout !== 'quick') {
        console.log('🎨 Layout - opening quick flyout for quick filter');
        this.openFlyout('quick');
      }
      this.suppressNextNoteSelection = false;
    } else {
      // No filters -> show all
      if (this.folderFilter || this.tagFilter || this.quickLinkFilter) {
        this.folderFilter = null;
        this.tagFilter = null;
        this.quickLinkFilter = null;
        if (!hasNote) this.autoSelectFirstNote();
      }
      this.suppressNextNoteSelection = false;
      // Close any open flyout when no filters
      if (this.hoveredFlyout) {
        console.log('🎨 Layout - closing flyout (no active filters)');
        this.scheduleCloseFlyout(0);
      }
    }
    
    console.log('🎨 Layout filters after:', {
      tagFilter: this.tagFilter,
      folderFilter: this.folderFilter, 
      quickLinkFilter: this.quickLinkFilter,
      hoveredFlyout: this.hoveredFlyout
    });
  });
  // Auto-select first note when filters change
  private autoSelectFirstNote() {
    const filteredNotes = this.getFilteredNotes();
    if (filteredNotes.length > 0 && filteredNotes[0].id !== this.selectedNoteId) {
      this.noteSelected.emit(filteredNotes[0].id);
    }
  }
  private getFilteredNotes(): Note[] {
    const q = (this.listQuery || '').toLowerCase().trim();
    const folder = (this.folderFilter || '').toLowerCase().replace(/^\/+|\/+$/g, '');
    const tag = (this.tagFilter || '').toLowerCase();
    const quickLink = this.quickLinkFilter;
    let list = this.vault.allNotes();
    // Exclude trash notes by default unless specifically viewing trash
    if (folder !== '.trash') {
      list = list.filter(n => {
        const filePath = (n.filePath || n.originalPath || '').toLowerCase().replace(/\\/g, '/');
        return !filePath.startsWith('.trash/') && !filePath.includes('/.trash/');
      });
    }
    if (folder) {
      if (folder === '.trash') {
        // All files anywhere under .trash (including subfolders)
        list = list.filter(n => {
          const filePath = (n.filePath || n.originalPath || '').toLowerCase().replace(/\\/g, '/');
          return filePath.startsWith('.trash/') || filePath.includes('/.trash/');
        });
      } else {
        list = list.filter(n => {
          const originalPath = (n.originalPath || '').toLowerCase().replace(/^\/+|\/+$/g, '');
          return originalPath === folder || originalPath.startsWith(folder + '/');
        });
      }
    }
    if (tag) {
      list = list.filter(n => Array.isArray(n.tags) && n.tags.some(t => (t || '').toLowerCase() === tag));
    }
    // Apply Quick Link filter
    if (quickLink) {
      list = list.filter(n => {
        const frontmatter = n.frontmatter || {};
        return frontmatter[quickLink] === true;
      });
    }
    // Apply query if present
    if (q) {
      list = list.filter(n => {
        const title = (n.title || '').toLowerCase();
        const filePath = (n.filePath || '').toLowerCase();
        return title.includes(q) || filePath.includes(q);
      });
    }
    // Sort by most recent first (same as notes-list component)
    const parseDate = (s?: string) => (s ? Date.parse(s) : 0) || 0;
    const score = (n: Note) => n.mtime || parseDate(n.updatedAt) || parseDate(n.createdAt) || 0;
    return [...list].sort((a, b) => (score(b) - score(a)));
  }
  ngAfterViewInit(): void {
    queueMicrotask(() => this.inPageSearch.setRoot(this.pageRoot?.nativeElement || null));
  }
  @HostListener('document:keydown', ['$event'])
  onKeydown(e: KeyboardEvent) {
    const isFind = (e.ctrlKey || e.metaKey) && (e.key === 'f' || e.key === 'F');
    if (isFind) {
      e.preventDefault();
      this.openInPageSearch();
    } else if (e.key === 'Escape' && this.inPageSearch.openState()) {
      this.inPageSearch.close();
    } else if (e.key === 'Enter' && this.inPageSearch.openState()) {
      if (e.shiftKey) this.inPageSearch.prev(); else this.inPageSearch.next();
      e.preventDefault();
    }
  }
  openInPageSearch(): void {
    this.inPageSearch.open();
    document.dispatchEvent(new CustomEvent('ov-search-focus'));
    this.inPageSearch.setRoot(this.pageRoot?.nativeElement || null);
  }
  onQueryChange(query: string) {
    this.listQuery = query;
    // Only auto-select when query is cleared; while typing keep focus in search (handled by notes-list)
    if (!query) {
      this.autoSelectFirstNote();
    }
    // Sync URL search term
    this.urlState.updateSearch(query);
  }
  toggleNoteFullScreen(): void {
    this.noteFullScreen = !this.noteFullScreen;
    document.body.classList.toggle('note-fullscreen-active', this.noteFullScreen);
  }
  /** Reuse the same behavior when a global fullscreen request event is dispatched */
  @HostListener('window:noteFullScreenRequested', ['$event'])
  onNoteFullScreenRequested(_evt: CustomEvent) {
    this.toggleNoteFullScreen();
  }
  nextTab() {
    const order: Array<'sidebar' | 'list' | 'page' | 'toc'> = ['sidebar', 'list', 'page', 'toc'];
    const idx = order.indexOf(this.mobileNav.activeTab());
    const next = order[Math.min(order.length - 1, idx + 1)] as any;
    this.mobileNav.setActiveTab(next);
  }
  prevTab() {
    const order: Array<'sidebar' | 'list' | 'page' | 'toc'> = ['sidebar', 'list', 'page', 'toc'];
    const idx = order.indexOf(this.mobileNav.activeTab());
    const prev = order[Math.max(0, idx - 1)] as any;
    this.mobileNav.setActiveTab(prev);
  }
  async onOpenNote(target: string) {
    try { console.debug('[Nimbus] onOpenNote', target); } catch {}
    let filePath: string | null = null;
    let noteId: string = target;
    try {
      const looksLikePath = /[/\\]/.test(target) || /\.[a-z0-9]+$/i.test(target);
      if (looksLikePath) {
        filePath = target.replace(/\\/g, '/');
        try { await this.vault.ensureNoteLoadedByPath(filePath); } catch {}
        try { noteId = this.vault.buildSlugIdFromPath(filePath); } catch {}
      } else {
        await this.vault.ensureNoteLoadedById(target);
        const n = (this.vault.allNotes() || []).find(x => x.id === target);
        filePath = n?.filePath || this.vault.getFastMetaById(target)?.path || null;
      }
      if (filePath) {
        try { console.debug('[Nimbus] opening note path', filePath); } catch {}
        this.urlState.openNote(filePath);
      } else {
        try { console.warn('[Nimbus] onOpenNote: no filePath resolved for', target); } catch {}
      }
    } finally {
      try { console.debug('[Nimbus] emitting noteSelected', noteId); } catch {}
      this.noteSelected.emit(noteId);
    }
  }
  onClearFolderFromList() {
    this.folderFilter = null;
    this.urlState.clearFolderFilter();
  }
  onAboutSelected(): void {
    this.showAboutPanel = true;
  }
  onNoteCreated(noteId: string) {
    this.noteCreated.emit(noteId);
  }
  onNoteCreatedAndSelected(event: { id: string; filePath: string }) {
    this.noteCreatedAndSelected.emit(event);
  }
  onNoteSelectedMobile(noteId: string) {
    if (!noteId) return;
    this.noteSelected.emit(noteId);
    this.mobileNav.setActiveTab('page');
  }
  onFolderSelected(path: string) {
    this.folderFilter = path || null;
    // Reset other filters and search when focusing a folder to prevent residual constraints
    this.tagFilter = null;
    this.quickLinkFilter = null;
    this.listQuery = '';
    try { this.filters.clearKinds(); } catch {}
    try { this.filters.clearTags(); } catch {}
    this.autoSelectFirstNote();
    if (this.responsive.isMobile() || this.responsive.isTablet()) {
      this.mobileNav.setActiveTab('list');
    }
    // Reflect folder in URL
    if (path) {
      // Clear search in URL to avoid residual query re-applying via URL effect
      try { this.urlState.updateSearch(''); } catch {}
      this.urlState.filterByFolder(path);
    } else {
      this.urlState.resetState();
    }
  }
  onFolderSelectedFromDrawer(path: string) {
    this.folderFilter = path || null;
    // Reset other filters and search when focusing a folder to prevent residual constraints
    this.tagFilter = null;
    this.quickLinkFilter = null;
    this.listQuery = '';
    try { this.filters.clearKinds(); } catch {}
    try { this.filters.clearTags(); } catch {}
    this.autoSelectFirstNote();
    this.mobileNav.setActiveTab('list');
    this.mobileNav.sidebarOpen.set(false);
    if (path) {
      // Clear search in URL to avoid residual query re-applying via URL effect
      try { this.urlState.updateSearch(''); } catch {}
      this.urlState.filterByFolder(path);
    } else {
      this.urlState.resetState();
    }
  }
  onQuickLink(_id: string) {
    const suppressAutoSelect = _id === 'all' || _id === 'favorites';
    this.suppressNextNoteSelection = suppressAutoSelect;
    if (_id === 'all') {
      // Show all pages: clear filters and focus list
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = null;
      this.listQuery = '';
      // Clear local filters (kinds, cumulative tags) to avoid conflicting filters
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      this.urlState.setQuickWithMarkdown('all');
    } else if (_id === 'publish') {
      // Filter by publish: true
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = 'publish';
      this.listQuery = '';
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      const label = this.mapInternalQuickToUrl('publish');
      if (label) {
        this.urlState.setQuickWithMarkdown(label);
      }
    } else if (_id === 'favorites') {
      // Filter by favoris: true
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = 'favoris';
      this.listQuery = '';
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      const label = this.mapInternalQuickToUrl('favoris');
      if (label) {
        this.urlState.setQuickWithMarkdown(label);
      }
    } else if (_id === 'templates') {
      // Filter by template: true
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = 'template';
      this.listQuery = '';
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      const label = this.mapInternalQuickToUrl('template');
      if (label) {
        this.urlState.setQuickWithMarkdown(label);
      }
    } else if (_id === 'tasks') {
      // Filter by task: true
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = 'task';
      this.listQuery = '';
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      const label = this.mapInternalQuickToUrl('task');
      if (label) {
        this.urlState.setQuickWithMarkdown(label);
      }
    } else if (_id === 'drafts') {
      // Filter by draft: true
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = 'draft';
      this.listQuery = '';
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      const label = this.mapInternalQuickToUrl('draft');
      if (label) {
        this.urlState.setQuickWithMarkdown(label);
      }
    } else if (_id === 'private') {
      // Filter by private: true
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = 'private';
      this.listQuery = '';
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      const label = this.mapInternalQuickToUrl('private');
      if (label) {
        this.urlState.setQuickWithMarkdown(label);
      }
    } else if (_id === 'archive') {
      // Filter by archive: true
      this.folderFilter = null;
      this.tagFilter = null;
      this.quickLinkFilter = 'archive';
      this.listQuery = '';
      try { this.filters.clearKinds(); } catch {}
      try { this.filters.clearTags(); } catch {}
      if (!this.responsive.isDesktop()) {
        this.mobileNav.setActiveTab('list');
      }
      this.scheduleCloseFlyout(150);
      const label = this.mapInternalQuickToUrl('archive');
      if (label) {
        this.urlState.setQuickWithMarkdown(label);
      }
    }
    // Auto-select first note after filter changes
    if (!this.suppressNextNoteSelection) {
      this.autoSelectFirstNote();
    }
    this.suppressNextNoteSelection = false;
  }
  onTagSelected(tagName: string) {
    const norm = (tagName || '').replace(/^#/, '').trim().toLowerCase();
    if (!norm) return;
    this.tagFilter = norm;
    this.folderFilter = null; // clear folder when focusing tag
    // Clear other filters and search to focus on tag results
    this.quickLinkFilter = null;
    this.listQuery = '';
    // Auto-select first note after filter changes
    this.autoSelectFirstNote();
    // Ensure the list is visible: exit fullscreen if active
    if (this.noteFullScreen) {
      this.noteFullScreen = false;
      document.body.classList.remove('note-fullscreen-active');
    }
    // Bubble up for global handlers (keeps parity with right sidebar tags)
    this.tagClicked.emit(norm);
    if (!this.responsive.isDesktop()) {
      this.mobileNav.setActiveTab('list');
    }
    // If from flyout, do not close immediately; small delay allows click feedback
    this.scheduleCloseFlyout(200);
    // Reflect in URL using original (non-normalized) tag label
    if (tagName) {
      this.urlState.filterByTag(tagName.replace(/^#/, '').trim());
    }
  }
  openFlyout(which: 'quick' | 'folders' | 'tags' | 'trash') {
    this.cancelCloseFlyout();
    this.hoveredFlyout = which;
  }
  scheduleCloseFlyout(delay = 200) {
    this.cancelCloseFlyout();
    this.flyoutCloseTimer = setTimeout(() => {
      this.hoveredFlyout = null;
      this.flyoutCloseTimer = null;
    }, delay);
  }
  cancelCloseFlyout() {
    if (this.flyoutCloseTimer) {
      clearTimeout(this.flyoutCloseTimer);
      this.flyoutCloseTimer = null;
    }
  }
  onMarkdownPlaygroundSelected(): void {
    if (this.responsive.isMobile()) {
      this.mobileNav.setActiveTab('page');
    }
    this.markdownPlaygroundSelected.emit();
  }
  onTestsPanelSelected(): void {
    if (this.responsive.isMobile()) {
      this.mobileNav.setActiveTab('page');
    }
    this.testsPanelRequested.emit();
  }
  onTestsExcalidrawSelected(): void {
    if (this.responsive.isMobile()) {
      this.mobileNav.setActiveTab('page');
    }
    this.testsExcalidrawRequested.emit();
  }
  onParametersOpen(): void {
    this.parametersOpened.emit();
  }
  onTocNavigate(headingId: string): void {
    // Ensure the page view is visible so the scroll container exists
    this.mobileNav.setActiveTab('page');
    
    // Close the TOC overlay immediately
    if (this.mobileNav.tocOpen()) {
      this.mobileNav.toggleToc();
    }
    
    // Wait for DOM to update before scrolling
    setTimeout(() => {
      this.navigateHeading.emit(headingId);
    }, 100);
  }
  onHelpPageSelected(): void {
    this.helpPageRequested.emit();
  }
  onClearQuickLinkFilter(): void {
    this.folderFilter = null;
    this.tagFilter = null;
    this.quickLinkFilter = null;
    this.listQuery = '';
    this.autoSelectFirstNote();
  }
}