import { Component, EventEmitter, Output, input, signal, computed, effect, inject, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ScrollingModule, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { PaginationService, NoteMetadata } from '../../services/pagination.service';
import { VaultService } from '../../../services/vault.service';
import { FileTypeDetectorService } from '../../../services/file-type-detector.service';
import { TagFilterStore } from '../../core/stores/tag-filter.store';
import { NotesListStateService, SortBy, ViewMode } from '../../services/notes-list-state.service';
import { FilterService } from '../../services/filter.service';
import { NoteContextMenuService } from '../../services/note-context-menu.service';
import { EditorStateService } from '../../../services/editor-state.service';
import { NoteContextMenuComponent } from '../../../components/note-context-menu/note-context-menu.component';
import { WarningPanelComponent } from '../../components/warning-panel/warning-panel.component';
import { FilterBadgeComponent } from '../../components/filter-badge/filter-badge.component';
import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrollable-overlay.directive';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
  selector: 'app-paginated-notes-list',
  standalone: true,
  imports: [CommonModule, ScrollingModule, ScrollableOverlayDirective, NoteContextMenuComponent, WarningPanelComponent, FilterBadgeComponent],
  template: `
    
      
      
      
      
        
          
          
            
            - 
              
              
              
              
                
                {{ typeIcon(note.filePath) }}
                {{ note.title }}
               
              
              
                
                {{ typeIcon(note.filePath) }}
                
                  {{ note.title }}
                  {{ note.filePath }}
                 
               
              
              
                
                {{ typeIcon(note.filePath) }}
                
                  {{ note.title }}
                  {{ note.filePath }}
                 
               
             
            
            - 
              
            
 
            
            -  0" class="p-4 text-center text-muted min-h-[60px] flex items-center justify-center">
              {{ totalLoaded() }} notes chargées
            
 
            
            - 
              Aucune note trouvée
            
 
          
        
       
     
    
    
    
    
    
  `,
  styles: [`
    :host {
      display: block;
      height: 100%;
      min-height: 0;
      background: var(--list-panel-bg);
      position: relative;
      z-index: 0;
    }
    /* Subtle vertical depth overlay */
    :host::before {
      content: "";
      position: absolute;
      inset: 0;
      pointer-events: none;
      background: linear-gradient(
        to bottom,
        color-mix(in oklab, var(--card) 100%, transparent 0%) 0%,
        color-mix(in oklab, var(--card) 96%, black 0%) 35%,
        color-mix(in oklab, var(--card) 92%, black 0%) 100%
      );
      opacity: 0.6;
    }
    /* Theming variables per color scheme */
    :host {
      --row-radius: 8px;
      --row-pad-v: 12px;
      --row-pad-h: 16px;
      --row-gap: 2px;
      --active-line: var(--primary, #3b82f6);
      --meta-color: var(--text-muted);
      --row-bg: color-mix(in oklab, var(--card) 97%, black 0%);
      --row-bg-hover: color-mix(in oklab, var(--card) 100%, white 6%);
      --row-shadow-active: 0 2px 10px color-mix(in oklab, var(--active-line) 18%, transparent 82%);
      --list-panel-bg: color-mix(in oklab, var(--card) 92%, black 8%);
    }
    :host-context(html.dark) {
      --row-bg: color-mix(in oklab, var(--card) 94%, white 0%);
      --row-bg-hover: color-mix(in oklab, var(--card) 90%, white 10%);
      --list-panel-bg: color-mix(in oklab, var(--card) 86%, black 14%);
    }
    :host-context(html:not(.dark)) {
      --row-bg: color-mix(in oklab, var(--card) 94%, black 6%);
      --row-bg-hover: color-mix(in oklab, var(--card) 90%, black 10%);
      --list-panel-bg: color-mix(in oklab, var(--card) 96%, black 4%);
    }
    cdk-virtual-scroll-viewport {
      height: 100%;
    }
    /* Notes list and rows (match non-virtual list) */
    .notes-list {
      margin: 0;
      padding: 2px 0;
      list-style: none;
    }
    .note-row {
      position: relative;
      margin: var(--row-gap) 1px;
      border-radius: var(--row-radius);
      background: var(--row-bg);
      transition: all 0.2s ease-in-out;
      min-height: 60px;
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
    .note-row:hover { background: var(--row-bg-hover); }
    .note-row.active::before,
    .note-row.active::after {
      content: "";
      position: absolute;
      left: 0; right: 0; height: 2px;
      background: var(--active-line);
      border-radius: 2px;
    }
    .note-row.active::before { top: 0; }
    .note-row.active::after { bottom: 0; }
    .note-row.active { box-shadow: var(--row-shadow-active); }
    .note-inner { padding: var(--row-pad-v) var(--row-pad-h); }
    .title { color: var(--text-main, #111); font-weight: 500; }
    :host-context(html.dark) .title { color: var(--text-main, #e5e7eb); }
    .note-row.active .title { font-weight: 600; }
    .meta { color: var(--meta-color, #6b7280); opacity: 0.8; }
    :host-context(html.dark) .meta { color: var(--meta-color, #94a3b8); opacity: 0.9; }
    .excerpt { color: var(--meta-color); opacity: 0.75; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; text-overflow: ellipsis; }
    :host::before { z-index: 0; }
    /* Action buttons container */
    .action-buttons { position: relative; display: flex; align-items: center; justify-content: space-between; width: 100%; gap: 0.5rem; }
    /* Enhanced note card with color indicator and action buttons */
    .note-card { transition: all 0.3s ease-in-out; background-repeat: no-repeat; background-size: 100% 120px; background-position: top center; }
    .note-card:hover { transform: translateY(-1px); }
    /* Color dot indicator */
    .note-color-dot { width: 8px; height: 8px; border-radius: 50%; box-shadow: 0 0 0 1px color-mix(in oklab, var(--text-main) 15%, transparent 85%); transition: all 0.2s ease-in-out; }
    .note-row:hover .note-color-dot { box-shadow: 0 0 0 2px color-mix(in oklab, var(--text-main) 25%, transparent 75%); }
    /* Action buttons */
    .note-card-actions { pointer-events: auto; }
    .action-btn { display: inline-flex; align-items: center; justify-content: center; cursor: pointer; font-size: 0; }
    .action-btn.edit { color: var(--primary, #3b82f6); }
    .action-btn.delete { color: #dc2626; }
    :host-context(html.dark) .action-btn.delete { color: #ef4444; }
  `]
})
export class PaginatedNotesListComponent implements OnInit, OnDestroy {
  private paginationService = inject(PaginationService);
  private store = inject(TagFilterStore);
  private vault = inject(VaultService);
  private fileTypes = inject(FileTypeDetectorService);
  readonly state = inject(NotesListStateService);
  readonly filter = inject(FilterService);
  readonly contextMenu = inject(NoteContextMenuService);
  private editorState = inject(EditorStateService);
  private destroy$ = new Subject();
  @ViewChild(CdkVirtualScrollViewport) viewport?: CdkVirtualScrollViewport;
  // Inputs
  folderFilter = input(null);
  query = input('');
  tagFilter = input(null);
  quickLinkFilter = input<'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | null>(null);
  selectedId = input(null);
  kindFilter = input<'image' | 'video' | 'pdf' | 'markdown' | 'excalidraw' | 'code' | 'all' | null>(null);
  // Outputs
  @Output() openNote = new EventEmitter();
  @Output() queryChange = new EventEmitter();
  @Output() clearQuickLinkFilter = new EventEmitter();
  // Local state
  private q = signal('');
  selectedNoteId = signal(null);
  activeTag = signal(null);
  sortMenuOpen = signal(false);
  viewModeMenuOpen = signal(false);
  readonly sortOptions: SortBy[] = ['title', 'created', 'updated'];
  readonly viewModes: ViewMode[] = ['compact', 'comfortable', 'detailed'];
  // Delete warning modal state
  deleteWarningOpen = signal(false);
  private deleteTargetId: string | null = null;
  // Pagination state
  paginatedNotes = this.paginationService.allItems;
  isLoadingMore = this.paginationService.isLoadingMore;
  hasMore = this.paginationService.hasMore;
  totalLoaded = this.paginationService.totalLoaded;
  canLoadMore = this.paginationService.canLoadMore;
  // Visible notes with fallback and filters
  visibleNotes = computed(() => {
    let items = this.paginatedNotes();
    let usedFallback = false;
    const vaultNotes = (() => {
      try { return this.vault.allNotes() || []; } catch { return []; }
    })();
    const byId = new Map(vaultNotes.map(n => [n.id, n]));
    if (!items || items.length === 0) {
      try {
        const all = this.vault.allNotes();
        items = (all || []).map(n => ({
          id: n.id,
          title: n.title,
          filePath: n.filePath,
          createdAt: n.createdAt as any,
          updatedAt: (n.updatedAt as any) || (n.mtime ? new Date(n.mtime).toISOString() : '')
        }));
        usedFallback = true;
      } catch {
        items = [];
      }
    }
    // Folder filter
    const folder = (this.folderFilter() || '').toLowerCase().replace(/^\/+|\/+$/g, '');
    if (folder) {
      if (folder === '.trash') {
        items = items.filter(n => {
          const fp = (n.filePath || '').toLowerCase().replace(/\\/g, '/');
          return fp.startsWith('.trash/') || fp.includes('/.trash/');
        });
      } else {
        items = items.filter(n => {
          const op = (n.filePath || '').toLowerCase().replace(/^\/+|\/+$/g, '');
          return op === folder || op.startsWith(folder + '/');
        });
      }
    } else {
      // Exclude trash by default
      items = items.filter(n => {
        const fp = (n.filePath || '').toLowerCase().replace(/\\/g, '/');
        return !fp.startsWith('.trash/') && !fp.includes('/.trash/');
      });
    }
    // Kind filters (FilterService multi-kinds first; fallback to single kindFilter)
    const kinds = this.filter.kinds();
    const urlKind = this.kindFilter();
    let allowedKinds = new Set(kinds.length > 0 ? kinds : (urlKind && urlKind !== 'all' ? [urlKind] : []));
    // Folder/Trash views must show all types unless quick/tag constrain to markdown
    const folderActive = !!folder;
    const quickActive = !!this.quickLinkFilter();
    const tagActive = !!(this.tagFilter() || '').trim() || this.filter.tags().length > 0;
    if (folderActive && !quickActive && !tagActive) {
      allowedKinds = new Set(); // no restriction in folder/trash
    }
    if (allowedKinds.size > 0) {
      items = items.filter(n => Array.from(allowedKinds).some(k => this.matchesKind(n.filePath, k as any)));
    }
    // Query filtering (always apply client-side as extra guard)
    const q = (this.q() || '').toLowerCase().trim();
    if (q) {
      items = items.filter(n => (n.title || '').toLowerCase().includes(q) || (n.filePath || '').toLowerCase().includes(q));
    }
    // Tag and Quick Link filters using vault metadata when available
    const urlTag = (this.tagFilter() || '').toLowerCase();
    const localTags = this.filter.tags().map(t => (t || '').toLowerCase());
    const quick = this.quickLinkFilter();
    if (urlTag || localTags.length > 0) {
      items = items.filter(n => {
        const full = byId.get(n.id);
        const ntags: string[] = Array.isArray(full?.tags) ? full.tags.map((t: string) => (t || '').toLowerCase()) : [];
        if (urlTag && !ntags.includes(urlTag)) return false;
        for (const t of localTags) { if (!ntags.includes(t)) return false; }
        // Tags view must show markdown only
        return this.matchesKind(n.filePath, 'markdown');
      });
    }
    if (quick) {
      items = items.filter(n => {
        const full = byId.get(n.id);
        const fm = full?.frontmatter || {};
        return fm[quick] === true && this.matchesKind(n.filePath, 'markdown');
      });
    }
    // If allowed kinds include any non-markdown type OR no kinds selected at all (default 'all'),
    // ensure those files appear even if pagination didn't include them (server may return only markdown)
    const needMergeForKinds = (allowedKinds.size > 0 && Array.from(allowedKinds).some(k => k !== 'markdown'))
      || (allowedKinds.size === 0 && !quick && !tagActive); // default 'all' and no quick/tag constraint
    if (needMergeForKinds) {
      const present = new Set(items.map(n => n.id));
      for (const full of vaultNotes) {
        const t = this.fileTypes.getViewerType(full.filePath, full.rawContent ?? full.content ?? '');
        const allowByKind = allowedKinds.size === 0 ? true : allowedKinds.has(t);
        if (allowByKind && !present.has(full.id)) {
          // Apply same folder filter and tag/quick constraints
          const fp = (full.filePath || '').toLowerCase().replace(/\\/g, '/');
          const op = (full.filePath || '').toLowerCase().replace(/^\/+|\/+$/g, '');
          const includeByFolder = folder
            ? (folder === '.trash'
                ? (fp.startsWith('.trash/') || fp.includes('/.trash/'))
                : (op === folder || op.startsWith(folder + '/')))
            : (!fp.startsWith('.trash/') && !fp.includes('/.trash/'));
          if (!includeByFolder) continue;
          const ntags: string[] = Array.isArray(full.tags) ? full.tags.map((x: string) => (x || '').toLowerCase()) : [];
          if (urlTag && !ntags.includes(urlTag)) continue;
          let okLocal = true; for (const t of localTags) { if (!ntags.includes(t)) { okLocal = false; break; } }
          if (!okLocal) continue;
          if (quick) {
            const fm = full.frontmatter || {};
            if (fm[quick] !== true) continue;
          }
          if (q) {
            const titleLc = (full.title || '').toLowerCase();
            const pathLc = (full.filePath || '').toLowerCase();
            if (!titleLc.includes(q) && !pathLc.includes(q)) continue;
          }
          items.push({ id: full.id, title: full.title, filePath: full.filePath, createdAt: (full as any).createdAt, updatedAt: (full as any).updatedAt || (full.mtime ? new Date(full.mtime).toISOString() : '') });
          present.add(full.id);
        }
      }
    }
    // Sorting (title/created/updated) like old list
    const parseDate = (s?: string) => (s ? Date.parse(s) : 0) || 0;
    const sortBy = this.state.sortBy();
    items = [...items].sort((a, b) => {
      switch (sortBy) {
        case 'title':
          return (a.title || '').localeCompare(b.title || '');
        case 'created':
          return parseDate(b.createdAt) - parseDate(a.createdAt);
        case 'updated':
        default:
          {
            const mb = byId.get(b.id)?.mtime; const ma = byId.get(a.id)?.mtime;
            const ub = parseDate(b.updatedAt) || (mb ? Number(mb) : 0);
            const ua = parseDate(a.updatedAt) || (ma ? Number(ma) : 0);
            return ub - ua;
          }
      }
    });
    return items;
  });
  // Effects
  private syncQuery = effect(() => {
    this.q.set(this.query() || '');
    // If external query changes (e.g., URL/state), refresh pagination to match
    const current = this.paginationService.getSearchTerm();
    const next = this.query() || '';
    if (current !== next) {
      this.paginationService.search(next);
    }
  });
  private syncTagFromStore = effect(() => {
    const inputTag = this.tagFilter();
    if (inputTag !== null && inputTag !== undefined) {
      this.activeTag.set(inputTag || null);
      return;
    }
    this.activeTag.set(this.store.get());
  });
  ngOnInit() {
    // Load initial page with incoming query
    this.paginationService.loadInitial(this.query() || '');
  }
  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
  // Handle virtual scroll
  onScroll(index: number) {
    const items = this.visibleNotes();
    // Load more when approaching the end (20 items before the end)
    if (index > items.length - 20 && this.canLoadMore()) {
      this.paginationService.loadNextPage();
    }
  }
  // Select a note
  selectNote(note: NoteMetadata) {
    this.selectedNoteId.set(note.id);
    this.openNote.emit(note.id);
  }
  // Search
  onQuery(v: string) {
    this.q.set(v);
    this.queryChange.emit(v);
    // Trigger search with pagination
    this.paginationService.search(v);
  }
  onSearchEnter(): void {
    const first = this.visibleNotes()[0];
    if (first) this.openNote.emit(first.id);
  }
  // Clear tag filter
  clearTagFilter(): void {
    this.activeTag.set(null);
    if (this.tagFilter() == null) {
      this.store.set(null);
    }
  }
  // Track by function for virtual scroll
  trackByFn(index: number, item: NoteMetadata): string {
    return item.id;
  }
  // Quick link display
  getQuickLinkDisplay(quickLink: string): { icon: string; name: string } | null {
    const displays: Record = {
      'favoris': { icon: '❤️', name: 'Favoris' },
      'publish': { icon: '🌐', name: 'Publish' },
      'draft': { icon: '📝', name: 'Draft' },
      'template': { icon: '📑', name: 'Template' },
      'task': { icon: '🗒️', name: 'Task' },
      'private': { icon: '🔒', name: 'Private' },
      'archive': { icon: '🗃️', name: 'Archive' }
    };
    return displays[quickLink] || null;
  }
  // Helpers
  private matchesKind(filePath: string, kind: 'image' | 'video' | 'pdf' | 'markdown' | 'excalidraw' | 'code'): boolean {
    try {
      const t = this.fileTypes.getViewerType(filePath, '');
      return t === kind;
    } catch {
      return true;
    }
  }
  // UI helpers
  getListItemClasses(): string {
    const mode = this.state.viewMode();
    if (mode === 'compact') return 'px-3 py-1.5';
    if (mode === 'detailed') return 'p-3 space-y-1.5';
    return 'p-3';
  }
  // Color and gradient
  private getFullNoteById(id: string): any | null {
    try {
      const n = (this.vault as any).getNoteById?.(id);
      if (n) return n;
    } catch {}
    try {
      const list = this.vault.allNotes() || [];
      for (const n of list) if ((n as any).id === id) return n;
    } catch {}
    return null;
  }
  getNoteColorById(id: string): string {
    const full = this.getFullNoteById(id);
    return full?.frontmatter?.color || 'var(--text-muted)';
  }
  getNoteGradientStyleById(id: string): Record | null {
    const full = this.getFullNoteById(id);
    const color = full?.frontmatter?.color;
    if (!color) return null;
    const hexMatch = /^#([0-9a-fA-F]{6})$/.exec(color);
    let gradientColor = color;
    if (hexMatch) {
      const hex = hexMatch[1];
      const r = parseInt(hex.slice(0,2), 16);
      const g = parseInt(hex.slice(2,4), 16);
      const b = parseInt(hex.slice(4,6), 16);
      gradientColor = `rgba(${r}, ${g}, ${b}, 0.14)`;
    }
    return { backgroundImage: `linear-gradient(to left, ${gradientColor} 0%, transparent 65%)` } as Record;
  }
  typeIcon(filePath: string): string {
    try {
      const t = this.fileTypes.getViewerType(filePath, '');
      switch (t) {
        case 'markdown': return '📝';
        case 'excalidraw': return '✏️';
        case 'pdf': return '📄';
        case 'image': return '🖼️';
        case 'video': return '🎬';
        case 'code': return '>';
        default: return '📎';
      }
    } catch { return '📎'; }
  }
  // Sort/View menus
  toggleSortMenu(): void { this.sortMenuOpen.set(!this.sortMenuOpen()); this.viewModeMenuOpen.set(false); }
  toggleViewModeMenu(): void { this.viewModeMenuOpen.set(!this.viewModeMenuOpen()); this.sortMenuOpen.set(false); }
  setSortBy(sort: SortBy): void { this.state.setSortBy(sort); this.sortMenuOpen.set(false); }
  setViewMode(mode: ViewMode): void { this.state.setViewMode(mode); this.viewModeMenuOpen.set(false); }
  getSortLabel(sort: SortBy): string {
    const labels: Record = { title: 'Titre', created: 'Date création', updated: 'Date modification' };
    return labels[sort];
  }
  getViewModeLabel(mode: ViewMode): string {
    const labels: Record = { compact: 'Compact', comfortable: 'Confortable', detailed: 'Détaillé' };
    return labels[mode];
  }
  // Context menu and delete
  openContextMenu(event: MouseEvent, noteId: string) {
    event.preventDefault(); event.stopPropagation();
    const full = this.getFullNoteById(noteId);
    if (full) this.contextMenu.openForNote(full, { x: event.clientX, y: event.clientY });
  }
  async onContextMenuAction(action: string) {
    const note = this.contextMenu.targetNote();
    if (!note) return;
    switch (action) {
      case 'duplicate': await this.contextMenu.duplicateNote(note); break;
      case 'share': await this.contextMenu.shareNote(note); break;
      case 'fullscreen': this.contextMenu.openFullScreen(note); break;
      case 'copy-link': await this.contextMenu.copyInternalLink(note); break;
      case 'favorite': await this.contextMenu.toggleFavorite(note); break;
      case 'info': this.contextMenu.showPageInfo(note); break;
      case 'readonly': await this.contextMenu.toggleReadOnly(note); break;
      case 'delete': this.openDeleteWarningById(note.id); break;
    }
  }
  async onContextMenuColor(color: string) {
    const note = this.contextMenu.targetNote();
    if (!note) return;
    await this.contextMenu.changeNoteColor(note, color);
  }
  openDeleteWarning(note: NoteMetadata) { this.openDeleteWarningById(note.id); }
  openDeleteWarningById(id: string) { this.deleteTargetId = id; this.deleteWarningOpen.set(true); }
  closeDeleteWarning() { this.deleteWarningOpen.set(false); this.deleteTargetId = null; }
  async confirmDelete() {
    const id = this.deleteTargetId; if (!id) { this.closeDeleteWarning(); return; }
    const full = this.getFullNoteById(id); if (!full) { this.closeDeleteWarning(); return; }
    try { await this.contextMenu.deleteNoteConfirmed(full); this.closeDeleteWarning(); this.contextMenu.close(); } catch {}
  }
  // Edit
  editNote(note: NoteMetadata): void {
    try {
      const full = this.getFullNoteById(note.id);
      if (full?.filePath) {
        const content = (full as any).rawContent ?? full.content ?? '';
        this.editorState.enterEditMode(full.filePath, content);
        this.openNote.emit(note.id);
      }
    } catch { this.openNote.emit(note.id); }
  }
  // Scroll selected into view
  private scrollToSelectedEffect = effect(() => {
    const id = this.selectedId();
    if (!id || !this.viewport) return;
    const idx = this.visibleNotes().findIndex(n => n.id === id);
    if (idx >= 0) {
      try { this.viewport.scrollToIndex(idx, 'smooth'); } catch {}
    }
  });
}