"use client";

import { useEffect, useState, useRef } from "react";
import { useSession } from "next-auth/react";
import { redirect } from "next/navigation";
import Navigation from "@/components/carnet/navigation";
import { NotesView } from "@/components/carnet/notes-view";
import { Editor } from "@/components/carnet/editor";
import { PanelResizer } from "@/components/carnet/panel-resizer";
import { useMediaQuery } from "@/hooks/use-media-query";
import { ContactsView } from '@/components/carnet/contacts-view';
import { MissionsView } from '@/components/carnet/missions-view';
import { MissionFilesView } from '@/components/carnet/mission-files-view';
import { MissionFilesManager } from '@/components/carnet/mission-files-manager';
import { X, Menu } from "lucide-react";
import { ContactDetails } from '@/components/carnet/contact-details';
import { parse as parseVCard, format as formatVCard } from 'vcard-parser';
import { format } from 'date-fns';
import { fr } from 'date-fns/locale';
import { PaneLayout } from './pane-layout';
import { notesCache, noteContentCache, foldersCache, invalidateFolderCache, invalidateNoteCache } from '@/lib/cache-utils';

interface Note {
  id: string;
  title: string;
  content: string;
  lastModified: string;
  type: string;
  mime: string;
  etag: string;
}

interface Contact {
  id: string;
  fullName?: string;
  email?: string;
  phone?: string;
  organization?: string;
  address?: string;
  notes?: string;
  group?: string;
}

export default function CarnetPage() {
  const { data: session, status } = useSession();
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [layoutMode, setLayoutMode] = useState<string>("item-selection");
  const [selectedNote, setSelectedNote] = useState<Note | null>(null);
  const [isMobile, setIsMobile] = useState(false);
  const [showNav, setShowNav] = useState(true);
  const [showNotes, setShowNotes] = useState(true);
  const [nextcloudFolders, setNextcloudFolders] = useState<string[]>([]);
  const [selectedFolder, setSelectedFolder] = useState<string>('Notes');
  const [notes, setNotes] = useState<Note[]>([]);
  const [isLoadingNotes, setIsLoadingNotes] = useState(true);
  const [contacts, setContacts] = useState<Contact[]>([]);
  const [selectedContact, setSelectedContact] = useState<Contact | null>(null);
  const [isLoadingContacts, setIsLoadingContacts] = useState(true);
  const [selectedMission, setSelectedMission] = useState<{ 
    id: string; 
    name: string; 
    creatorId?: string;
    isClosed?: boolean;
    missionUsers?: any[];
  } | null>(null);
  const [selectedMissionFile, setSelectedMissionFile] = useState<{ key: string; content: string } | null>(null);
  
  // Panel widths state
  const [navWidth, setNavWidth] = useState(220);
  const [notesWidth, setNotesWidth] = useState(400);
  const [isDraggingNav, setIsDraggingNav] = useState(false);
  const [isDraggingNotes, setIsDraggingNotes] = useState(false);

  // Check screen size
  const isSmallScreen = useMediaQuery("(max-width: 768px)");
  const isMediumScreen = useMediaQuery("(max-width: 1024px)");

  // Cache is now managed by cache-utils.ts

  useEffect(() => {
    const fetchNextcloudFolders = async () => {
      // Check cache first
      const cacheKey = session?.user?.id || 'default';
      const cachedFolders = foldersCache.get<string[]>(cacheKey);
      if (cachedFolders) {
        setNextcloudFolders(cachedFolders);
        return;
      }

      try {
        const response = await fetch('/api/storage/status');
        if (!response.ok) {
          const errorData = await response.json().catch(() => ({}));
          throw new Error(errorData.message || 'Failed to fetch storage folders');
        }
        const data = await response.json();
        const folders = data.folders || [];
        
        // Update cache
        foldersCache.set(cacheKey, folders);
        setNextcloudFolders(folders);
      } catch (err) {
        console.error('Error fetching storage folders:', err);
        setNextcloudFolders([]);
      }
    };

    if (status === "authenticated") {
      fetchNextcloudFolders();
    }
  }, [status, session?.user?.id]);

  useEffect(() => {
    if (status === "unauthenticated") {
      redirect("/signin");
    }
    if (status === "authenticated" && session?.user?.id) {
      // Initialize all folders when user logs in
      fetch('/api/storage/init', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        }
      }).then(response => {
        if (response.ok) {
          console.log('All folders initialized successfully');
        } else {
          console.error('Failed to initialize folders');
        }
      }).catch(error => {
        console.error('Error initializing folders:', error);
      });
    }
    if (status !== "loading") {
      setIsLoading(false);
    }
  }, [status, session?.user?.id]);

  useEffect(() => {
    if (isSmallScreen) {
      setIsMobile(true);
      setShowNav(false);
      setShowNotes(false);
    } else if (isMediumScreen) {
      setIsMobile(false);
      setShowNav(true);
      setShowNotes(false);
    } else {
      setIsMobile(false);
      setShowNav(true);
      setShowNotes(true);
    }
  }, [isSmallScreen, isMediumScreen]);

  useEffect(() => {
    console.log(`[useEffect] selectedFolder changed to: "${selectedFolder}"`);
    if (selectedFolder === 'Contacts') {
      // When "Contacts" is selected, show all contacts
      console.log(`[useEffect] Calling fetchContacts('Contacts')`);
      fetchContacts('Contacts');
    } else if (selectedFolder.endsWith('.vcf')) {
      // When a specific VCF file is selected, show its contacts
      console.log(`[useEffect] Calling fetchContacts('${selectedFolder}')`);
      fetchContacts(selectedFolder);
    } else {
      // For other folders (Notes, etc.), fetch notes
      console.log(`[useEffect] Calling fetchNotes() for folder: ${selectedFolder}`);
      fetchNotes();
    }
  }, [selectedFolder, session?.user?.id]);

  // Listen for note-saved events to refresh the list
  useEffect(() => {
    const handleNoteSaved = (event: CustomEvent) => {
      const folder = event.detail?.folder;
      if (folder && session?.user?.id) {
        console.log('Note saved event received, invalidating cache for folder:', folder);
        // Invalidate cache for this folder
        invalidateFolderCache(session.user.id, folder);
        // Fetch notes if this is the current folder
        if (selectedFolder.toLowerCase() === folder.toLowerCase()) {
          fetchNotes();
        }
      }
    };

    window.addEventListener('note-saved', handleNoteSaved as EventListener);
    return () => {
      window.removeEventListener('note-saved', handleNoteSaved as EventListener);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedFolder, session?.user?.id]);

  const parseVCardContent = (content: string): Contact[] => {
    try {
      console.log(`[parseVCardContent] Parsing VCF content, length: ${content.length}`);
      
      // Normalize line endings and split vCards
      // Replace \r\n with \n, then split by BEGIN:VCARD
      const normalizedContent = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
      
      // Split the content into individual vCards
      // Handle formats like: BEGIN:VCARD\n... or BEGIN:VCARDVERSION:3.0...
      const vcardSections = normalizedContent.split(/BEGIN:VCARD/i).filter(section => section.trim());
      console.log(`[parseVCardContent] Found ${vcardSections.length} vCard sections`);
      
      const parsed = vcardSections.map((section, index) => {
        try {
          // Reconstruct vCard content with proper formatting
          let vcardContent = 'BEGIN:VCARD\n';
          
          // Clean up the section and ensure proper line breaks
          let cleanedSection = section.trim();
          
          // Fix format where BEGIN:VCARD is directly followed by VERSION (no newline)
          cleanedSection = cleanedSection.replace(/^VERSION:/, 'VERSION:');
          
          // Ensure each field is on its own line
          cleanedSection = cleanedSection
            .replace(/([^\n])(VERSION:)/g, '$1\n$2')
            .replace(/([^\n])(UID:)/g, '$1\n$2')
            .replace(/([^\n])(FN:)/g, '$1\n$2')
            .replace(/([^\n])(EMAIL)/g, '$1\n$2')
            .replace(/([^\n])(TEL)/g, '$1\n$2')
            .replace(/([^\n])(ORG:)/g, '$1\n$2')
            .replace(/([^\n])(NOTE:)/g, '$1\n$2')
            .replace(/([^\n])(END:VCARD)/g, '$1\n$2');
          
          vcardContent += cleanedSection;
          
          // Ensure it ends with END:VCARD
          if (!vcardContent.trim().endsWith('END:VCARD')) {
            vcardContent += '\nEND:VCARD';
          }
          
          console.log(`[parseVCardContent] Processing vCard ${index + 1}, content preview:`, vcardContent.substring(0, 300));
          
          const vcard = parseVCard(vcardContent);
          
          // Extract contact properties with proper type handling
          const uid = vcard.uid?.[0]?.value;
          let fullName = vcard.fn?.[0]?.value;
          
          // If FN is not available, try to construct name from N field (Family;Given;Additional;Prefix;Suffix)
          if (!fullName && vcard.n?.[0]?.value) {
            const nameParts = vcard.n[0].value.split(';').filter(Boolean);
            // N format: Family;Given;Additional;Prefix;Suffix
            // Construct: Given Family or Family Given
            if (nameParts.length >= 2) {
              fullName = `${nameParts[1]} ${nameParts[0]}`.trim() || nameParts[0] || nameParts[1];
            } else if (nameParts.length === 1) {
              fullName = nameParts[0];
            }
          }
          
          // Fallback: try to extract from raw content if parser didn't work
          if (!fullName) {
            const fnMatch = section.match(/FN[;:]?([^\r\n]+)/i);
            if (fnMatch) {
              fullName = fnMatch[1].trim();
            } else {
              const nMatch = section.match(/N[;:]?([^\r\n]+)/i);
              if (nMatch) {
                const nameParts = nMatch[1].split(';').filter(Boolean);
                if (nameParts.length >= 2) {
                  fullName = `${nameParts[1]} ${nameParts[0]}`.trim() || nameParts[0] || nameParts[1];
                } else if (nameParts.length === 1) {
                  fullName = nameParts[0].trim();
                }
              }
            }
          }
          
          const email = vcard.email?.[0]?.value || vcard.email?.[0];
          const phone = vcard.tel?.[0]?.value || vcard.tel?.[0];
          const organization = vcard.org?.[0]?.value || vcard.org?.[0];
          const address = vcard.adr?.[0]?.value || (vcard.adr?.[0] ? JSON.stringify(vcard.adr[0]) : '');
          const notes = vcard.note?.[0]?.value || vcard.note?.[0];
          const group = vcard.categories?.[0]?.value || vcard.categories?.[0];
          
          console.log(`[parseVCardContent] Parsed contact ${index + 1}:`, { uid, fullName, email, phone, rawVCard: vcard });
          
          // Create a clean contact object
          const contact: Contact = {
            id: uid || Math.random().toString(36).substr(2, 9),
            fullName: fullName || email || 'Sans nom',
            email: email || '',
            phone: phone || '',
            organization: organization || '',
            address: typeof address === 'string' ? address : '',
            notes: notes || '',
            group: group || ''
          };
          
          return contact;
        } catch (parseError) {
          console.error(`[parseVCardContent] Error parsing vCard section ${index + 1}:`, parseError);
          return null;
        }
      }).filter((contact): contact is Contact => contact !== null);
      
      console.log(`[parseVCardContent] Successfully parsed ${parsed.length} contacts`);
      return parsed;
    } catch (error) {
      console.error('[parseVCardContent] Error parsing VCF content:', error);
      return [];
    }
  };

  const fetchContacts = async (folder: string) => {
    console.log(`[fetchContacts] Called with folder: ${folder}`);
    try {
      setIsLoadingContacts(true);
      
      // Use lowercase for consistency
      const folderLowercase = folder.toLowerCase();
      console.log(`[fetchContacts] Processing folder: ${folderLowercase}`); 
      
      // First, check if we're looking at a specific VCF file
      if (folder.endsWith('.vcf')) {
        const response = await fetch(`/api/storage/files/content?path=${encodeURIComponent(`user-${session?.user?.id}/${folderLowercase}/${folder}`)}`);
        if (response.ok) {
          const { content } = await response.json();
          const contacts = parseVCardContent(content);
          setContacts(contacts.map(contact => ({
            ...contact,
            group: folder.replace('.vcf', '')
          })));
        }
      } else {
        // If not a VCF file, list all VCF files in the folder
        console.log(`[fetchContacts] Fetching files from API for folder: ${folderLowercase}`);
        const response = await fetch(`/api/storage/files?folder=${folderLowercase}`);
        console.log(`[fetchContacts] API response status: ${response.status}`);
        if (response.ok) {
          const files = await response.json();
          console.log(`[fetchContacts] Found ${files.length} files in contacts folder`, files);
          
          // Filter VCF files - API returns { key, name, size, lastModified }
          const vcfFiles = files.filter((file: any) => 
            file.name?.endsWith('.vcf') || file.key?.endsWith('.vcf')
          );
          
          console.log(`[fetchContacts] Found ${vcfFiles.length} VCF files`, vcfFiles);
          
          // Parse VCF files and extract contact information
          const parsedContacts = await Promise.all(
            vcfFiles.map(async (file: any) => {
              try {
                // Use file.key (S3 key) or file.id as the path
                const fileKey = file.key || file.id;
                console.log(`[fetchContacts] Fetching content for VCF file: ${fileKey}`);
                
                const contentResponse = await fetch(`/api/storage/files/content?path=${encodeURIComponent(fileKey)}`);
                if (contentResponse.ok) {
                  const { content } = await contentResponse.json();
                  console.log(`[fetchContacts] VCF content preview (first 500 chars):`, content.substring(0, 500));
                  const contacts = parseVCardContent(content);
                  console.log(`[fetchContacts] Parsed ${contacts.length} contacts from ${fileKey}`, contacts);
                  return contacts.map(contact => ({
                    ...contact,
                    group: (file.name || file.key?.split('/').pop() || 'contacts')?.replace('.vcf', '')
                  }));
                } else {
                  console.error(`[fetchContacts] Failed to fetch content for ${fileKey}:`, contentResponse.status);
                }
                return [];
              } catch (error) {
                console.error('Error fetching VCF content:', error);
                return [];
              }
            })
          );
          
          // Flatten the array of contact arrays
          const allContacts = parsedContacts.flat().filter(Boolean);
          console.log(`[fetchContacts] Total contacts parsed: ${allContacts.length}`, allContacts);
          setContacts(allContacts);
          
          // Log state after setting
          setTimeout(() => {
            console.log(`[fetchContacts] Contacts state after setContacts:`, allContacts.length);
          }, 100);
        } else {
          console.error(`[fetchContacts] Failed to fetch files:`, response.status, await response.text().catch(() => ''));
          setContacts([]);
        }
      }
    } catch (error) {
      console.error('[fetchContacts] Error fetching contacts:', error);
      setContacts([]);
    } finally {
      setIsLoadingContacts(false);
      console.log(`[fetchContacts] Finished loading contacts, isLoadingContacts set to false`);
    }
  };

  // Fetch notes based on the selected folder
  const fetchNotes = async (skipCache = false) => {
    if (!session?.user?.id) {
      setIsLoadingNotes(false);
      return;
    }

    try {
      setIsLoadingNotes(true);
      
      // Convert folder name to lowercase for consistent storage access
      const folderLowercase = selectedFolder.toLowerCase();
      console.log(`[fetchNotes] Fetching notes from folder: ${folderLowercase}, skipCache: ${skipCache}`);
      
      // Check cache first (unless skipCache is true)
      const cacheKey = `${session.user.id}-${folderLowercase}`;
      if (!skipCache) {
        const cachedNotes = notesCache.get<Note[]>(cacheKey);
        if (cachedNotes) {
          console.log(`[fetchNotes] Using cached notes for ${folderLowercase} folder (${cachedNotes.length} notes)`);
          setNotes(cachedNotes);
          setIsLoadingNotes(false);
          return;
        } else {
          console.log(`[fetchNotes] No cache found for ${folderLowercase} folder, fetching from API`);
        }
      } else {
        console.log(`[fetchNotes] Skipping cache for ${folderLowercase} folder (skipCache=true)`);
      }
      
      // Fetch from API
      const response = await fetch(`/api/storage/files?folder=${folderLowercase}`);
      
      if (response.ok) {
        const data = await response.json();
        console.log(`[fetchNotes] Fetched ${data.length} files from ${folderLowercase} folder`, data);
        
        // Map API response to Note format
        // API returns: { key, name, size, lastModified }
        // Frontend expects: { id, title, content, lastModified, type, mime, etag }
        const mappedNotes: Note[] = data.map((file: any) => {
          // Extract title from filename (remove .md extension if present)
          let title = file.name?.replace(/\.md$/, '') || file.name || 'Untitled';
          
          // For Diary/Health folders, convert sanitized filename back to formatted title
          // Example: "16_janvier_2026" -> "16 janvier 2026"
          if ((folderLowercase === 'diary' || folderLowercase === 'health') && title.includes('_')) {
            // Check if it matches the date pattern: DD_mois_YYYY
            const datePattern = /^(\d{1,2})_([a-zéèêà]+)_(\d{4})$/i;
            const match = title.match(datePattern);
            if (match) {
              const day = match[1];
              const month = match[2];
              const year = match[3];
              // Capitalize first letter of month
              const monthCapitalized = month.charAt(0).toUpperCase() + month.slice(1);
              title = `${day} ${monthCapitalized} ${year}`;
            } else {
              // If pattern doesn't match, just replace underscores with spaces
              title = title.replace(/_/g, ' ');
            }
          }
          
          return {
            id: file.key || file.id || '',
            title: title,
            content: '', // Content will be loaded when note is selected
            lastModified: file.lastModified ? new Date(file.lastModified).toISOString() : new Date().toISOString(),
            type: 'file',
            mime: file.name?.endsWith('.md') ? 'text/markdown' : 'text/plain',
            etag: file.key || '' // Use key as etag for now
          };
        });
        
        // Remove duplicates based on id
        const uniqueNotes = mappedNotes.filter((note, index, self) => 
          index === self.findIndex(n => n.id === note.id)
        );
        
        console.log(`[fetchNotes] Mapped ${uniqueNotes.length} unique notes from ${folderLowercase} folder (${mappedNotes.length} total before deduplication)`);
        console.log(`[fetchNotes] Note titles:`, uniqueNotes.map(n => n.title));
        
        // Update state
        setNotes(uniqueNotes);
        
        // Update cache
        notesCache.set(cacheKey, uniqueNotes);
        console.log(`[fetchNotes] Cache updated for ${folderLowercase} folder with ${uniqueNotes.length} notes`);
      } else {
        const errorData = await response.json().catch(() => ({}));
        console.error('[fetchNotes] Error fetching notes:', errorData.message || response.statusText);
        setNotes([]);
      }
    } catch (error) {
      console.error('[fetchNotes] Error fetching notes:', error);
      setNotes([]);
    } finally {
      setIsLoadingNotes(false);
    }
  };

  // Handle saving changes to a note
  const handleSaveNote = async (note: Note) => {
    try {
      setIsSaving(true);
      
      // For Diary and Health, ensure title is formatted with date
      let noteTitle = note.title || 'Untitled';
      let fileKey: string | undefined;
      
      if (selectedFolder === 'Diary' || selectedFolder === 'Health') {
        // For Diary/Health, always use today's date as title (formatted for display)
        const today = new Date();
        const dateStr = format(today, 'yyyy-MM-dd'); // For filename matching
        const dateTitle = format(today, 'd MMMM yyyy', { locale: fr }); // For display: "16 janvier 2026"
        noteTitle = dateTitle;
        
        // If note.id is already set (from handleNewNote), use it directly
        // This ensures we use the same fileKey that was pre-set
        if (note.id && note.id.includes(`user-${session?.user?.id}/${selectedFolder.toLowerCase()}/`)) {
          fileKey = note.id;
          console.log(`[handleSaveNote] Using pre-set fileKey from note.id: ${fileKey}`);
        } else {
          // ALWAYS check if a note with this date already exists
          // This ensures we update the existing note instead of creating a duplicate
          console.log(`[handleSaveNote] Checking for existing note. Date: ${dateTitle}, DateStr: ${dateStr}, Notes count: ${notes.length}`);
          
          const existingNote = notes.find(n => {
            const title = n.title || '';
            const noteId = n.id || '';
            // Check multiple patterns to find the existing note
            return title === dateTitle || 
                   title === dateStr ||
                   title.startsWith(dateStr) || 
                   title.startsWith(dateTitle) ||
                   noteId.includes(dateStr) ||
                   noteId.includes(dateTitle.replace(/\s/g, '_')) ||
                   noteId.includes(dateTitle.replace(/\s/g, '-'));
          });
          
          if (existingNote) {
            // Update the existing note instead of creating a new one
            console.log(`[handleSaveNote] Found existing note for today, updating: ${existingNote.id}, title: ${existingNote.title}`);
            note.id = existingNote.id;
            noteTitle = existingNote.title || dateTitle; // Keep the existing title format
            // Use the existing note's id as the fileKey - this is critical!
            fileKey = existingNote.id;
            console.log(`[handleSaveNote] Using existing fileKey: ${fileKey}`);
          } else {
            // No existing note found, create new one with formatted date title
            // Sanitize the title to match the format used in S3
            const sanitizedTitle = dateTitle.replace(/[^a-zA-Z0-9._-]/g, '_');
            fileKey = `user-${session?.user?.id}/${selectedFolder.toLowerCase()}/${sanitizedTitle}.md`;
            console.log(`[handleSaveNote] No existing note found, creating new with fileKey: ${fileKey}`);
          }
        }
      } else {
        // For other folders (Bloc-notes)
        console.log(`[handleSaveNote] BLOC-NOTES: Starting save process`);
        console.log(`[handleSaveNote] BLOC-NOTES: note.id = "${note.id}"`);
        console.log(`[handleSaveNote] BLOC-NOTES: noteTitle = "${noteTitle}"`);
        console.log(`[handleSaveNote] BLOC-NOTES: note.title = "${note.title}"`);
        console.log(`[handleSaveNote] BLOC-NOTES: Current notes count: ${notes.length}`);
        console.log(`[handleSaveNote] BLOC-NOTES: Current notes:`, notes.map(n => ({ id: n.id, title: n.title })));
        
        // Refresh notes list to ensure we have the latest data
        console.log(`[handleSaveNote] BLOC-NOTES: Refreshing notes list...`);
        await fetchNotes(true);
        console.log(`[handleSaveNote] BLOC-NOTES: After refresh, notes count: ${notes.length}`);
        console.log(`[handleSaveNote] BLOC-NOTES: After refresh, notes:`, notes.map(n => ({ id: n.id, title: n.title })));
        
        // Check if the current note.id corresponds to an "Untitled" note
        // and if we're giving it a new title (renaming scenario)
        const isRenamingUntitled = note.id && 
                                   !note.id.startsWith('temp-') && 
                                   note.id.includes(`user-${session?.user?.id}/`) &&
                                   note.id.includes('/Untitled.md') &&
                                   noteTitle && 
                                   noteTitle.trim() !== '' && 
                                   noteTitle !== 'Untitled';
        
        console.log(`[handleSaveNote] BLOC-NOTES: isRenamingUntitled = ${isRenamingUntitled}`);
        if (isRenamingUntitled) {
          console.log(`[handleSaveNote] BLOC-NOTES: Detected renaming scenario`);
        }
        
        if (isRenamingUntitled) {
          // We're renaming an Untitled note to a new title
          const sanitizedTitle = noteTitle.replace(/[^a-zA-Z0-9._-]/g, '_');
          fileKey = `user-${session?.user?.id}/${selectedFolder.toLowerCase()}/${sanitizedTitle}.md`;
          console.log(`[handleSaveNote] BLOC-NOTES: Renaming Untitled note to "${noteTitle}": ${note.id} -> ${fileKey}`);
          // Store the old id to delete it later
          (note as any)._oldUntitledId = note.id;
          note.id = fileKey; // Update note.id to the new fileKey
        } else if (note.id && !note.id.startsWith('temp-') && note.id.includes(`user-${session?.user?.id}/`)) {
          // Note has a valid id and we're not renaming, use it directly
          fileKey = note.id;
          console.log(`[handleSaveNote] BLOC-NOTES: Using existing note id directly: ${fileKey}`);
        } else {
          console.log(`[handleSaveNote] BLOC-NOTES: Entering else branch (new note or temp id)`);
          // This is a new note or note with temp id
          // Strategy: If we have a title, check for existing note with that title
          // If no title or title is "Untitled", check for existing "Untitled" note
          // If we're updating from "Untitled" to a real title, find the "Untitled" note and update it
          
          if (noteTitle && noteTitle.trim() !== '' && noteTitle !== 'Untitled') {
            // Note has a real title, check if a note with this title already exists
            console.log(`[handleSaveNote] BLOC-NOTES: Note has real title: "${noteTitle}"`);
            const sanitizedTitle = noteTitle.replace(/[^a-zA-Z0-9._-]/g, '_');
            const expectedFileKey = `user-${session?.user?.id}/${selectedFolder.toLowerCase()}/${sanitizedTitle}.md`;
            console.log(`[handleSaveNote] BLOC-NOTES: Expected fileKey: ${expectedFileKey}`);
            
            const existingNoteWithTitle = notes.find(n => {
              const nTitle = n.title || '';
              const nId = n.id || '';
              // Check if title matches exactly or if the id matches the expected fileKey
              const matches = (nTitle === noteTitle && nTitle !== 'Untitled') || nId === expectedFileKey;
              if (matches) {
                console.log(`[handleSaveNote] BLOC-NOTES: Found matching note:`, { id: nId, title: nTitle });
              }
              return matches;
            });
            
            if (existingNoteWithTitle) {
              // Update the existing note with this title
              console.log(`[handleSaveNote] BLOC-NOTES: Found existing note with title "${noteTitle}", updating: ${existingNoteWithTitle.id}`);
              note.id = existingNoteWithTitle.id;
              fileKey = existingNoteWithTitle.id;
            } else {
              // Check if there's an "Untitled" note we should update (user added title to Untitled note)
              console.log(`[handleSaveNote] BLOC-NOTES: No note with title "${noteTitle}" found, checking for Untitled note...`);
              const untitledNote = notes.find(n => {
                const nTitle = n.title || '';
                const isUntitled = (nTitle === 'Untitled' || nTitle === '' || nTitle.trim() === '') && 
                       n.id && n.id.includes(`user-${session?.user?.id}/${selectedFolder.toLowerCase()}/`);
                if (isUntitled) {
                  console.log(`[handleSaveNote] BLOC-NOTES: Found Untitled note:`, { id: n.id, title: nTitle });
                }
                return isUntitled;
              });
              
              if (untitledNote) {
                // Rename the Untitled note with the new title
                // Use the new fileKey based on the new title
                console.log(`[handleSaveNote] BLOC-NOTES: Renaming Untitled note to "${noteTitle}": ${untitledNote.id} -> ${expectedFileKey}`);
                // Store the old id to delete it later
                const oldUntitledId = untitledNote.id;
                fileKey = expectedFileKey;
                note.id = fileKey; // Update note.id to the new fileKey
                // We'll delete the old Untitled file after saving
                // Store it in a variable accessible after the save
                (note as any)._oldUntitledId = oldUntitledId;
              } else {
                // No existing note found, create new one
                fileKey = expectedFileKey;
                console.log(`[handleSaveNote] BLOC-NOTES: No existing note found, creating new one with fileKey: ${fileKey}`);
              }
            }
          } else {
            console.log(`[handleSaveNote] BLOC-NOTES: Note has no title or title is "Untitled"`);
            // No title or title is "Untitled", check for existing Untitled note
            console.log(`[handleSaveNote] BLOC-NOTES: Searching for existing Untitled note...`);
            const untitledNote = notes.find(n => {
              const nTitle = n.title || '';
              const isUntitled = (nTitle === 'Untitled' || nTitle === '' || nTitle.trim() === '') && 
                     n.id && n.id.includes(`user-${session?.user?.id}/${selectedFolder.toLowerCase()}/`);
              if (isUntitled) {
                console.log(`[handleSaveNote] BLOC-NOTES: Found Untitled note:`, { id: n.id, title: nTitle });
              }
              return isUntitled;
            });
            
            if (untitledNote) {
              // Use existing Untitled note
              console.log(`[handleSaveNote] BLOC-NOTES: Using existing Untitled note: ${untitledNote.id}`);
              note.id = untitledNote.id;
              noteTitle = 'Untitled';
              fileKey = untitledNote.id;
            } else {
              // Create new Untitled note
              fileKey = `user-${session?.user?.id}/${selectedFolder.toLowerCase()}/Untitled.md`;
              console.log(`[handleSaveNote] BLOC-NOTES: No Untitled note found, creating new one: ${fileKey}`);
            }
          }
        }
      }
      
      if (!fileKey) {
        throw new Error('Cannot determine file key for saving note');
      }
      
      // Construct API payload with lowercase folder name
      const payload = {
        id: fileKey,
        title: noteTitle,
        content: note.content || '',
        folder: selectedFolder.toLowerCase(), // Use lowercase for storage consistency
        mime: "text/markdown"
      };
      
      console.log(`[handleSaveNote] File key for ${selectedFolder}: ${fileKey}`);
      console.log(`[handleSaveNote] Payload content length: ${payload.content.length} chars`);
      if (selectedFolder === 'Health') {
        console.log(`[handleSaveNote] Health payload content preview:`, payload.content.substring(0, 200));
      }
      
      // Use direct storage API endpoint
      const endpoint = '/api/storage/files';
      // For Diary/Health, always use PUT (we always have a fileKey, either from existing note or constructed)
      // For other folders, use PUT if note.id exists, otherwise POST
      const method = (selectedFolder === 'Diary' || selectedFolder === 'Health') 
        ? 'PUT' // Always PUT for Diary/Health since we always have a known fileKey
        : (note.id ? 'PUT' : 'POST');
      
      console.log(`Saving note to ${selectedFolder.toLowerCase()} using ${method}, title: ${noteTitle}, fileKey: ${fileKey}`);
      
      const response = await fetch(endpoint, {
        method,
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
      });
      
      console.log(`[handleSaveNote] Response status: ${response.status}, ok: ${response.ok}`);
      
      if (response.ok) {
        console.log(`[handleSaveNote] Save successful for ${selectedFolder}`);
        // If we renamed a note from Untitled to a title, delete the old Untitled file
        const oldUntitledId = (note as any)._oldUntitledId;
        if (oldUntitledId && oldUntitledId !== fileKey) {
          try {
            const deleteResponse = await fetch(`/api/storage/files`, {
              method: 'DELETE',
              headers: {
                'Content-Type': 'application/json'
              },
              body: JSON.stringify({
                id: oldUntitledId,
                folder: selectedFolder.toLowerCase()
              })
            });
            if (deleteResponse.ok) {
              console.log(`[handleSaveNote] Deleted old Untitled file: ${oldUntitledId}`);
            } else {
              console.warn(`[handleSaveNote] Failed to delete old Untitled file: ${oldUntitledId}`);
            }
          } catch (deleteError) {
            console.error('Error deleting old Untitled file:', deleteError);
            // Continue anyway, the new file was created successfully
          }
        }
        
        // Invalidate the cache for this folder to ensure fresh data on next fetch
        if (session?.user?.id) {
          invalidateFolderCache(session.user.id, selectedFolder);
        }
        
        // Update the content cache for this note
        if (payload.id) {
          noteContentCache.set(payload.id, payload.content);
        }
        
        // For Health folder, update selectedNote with the new content so the form reflects the saved data
        if (selectedFolder === 'Health' && selectedNote?.id === fileKey) {
          console.log(`[handleSaveNote] Updating selectedNote content for Health form`);
          setSelectedNote({
            ...selectedNote,
            content: payload.content,
            lastModified: new Date().toISOString()
          });
        }
        
        // Refresh the list of notes (skip cache to get fresh data)
        // Only refresh if not Health folder to avoid constant flickering during form updates
        // Health folder updates are handled by the form itself and don't need immediate list refresh
        if (selectedFolder !== 'Health') {
          fetchNotes(true);
        } else {
          console.log(`[handleSaveNote] Health folder - skipping fetchNotes to avoid flickering`);
        }
        
        // Log success for debugging - try to read response but don't fail if it's empty
        try {
          const responseText = await response.text();
          if (responseText) {
            const responseData = JSON.parse(responseText);
            console.log(`[handleSaveNote] Save successful, response:`, responseData);
          } else {
            console.log(`[handleSaveNote] Save successful (empty response)`);
          }
        } catch (parseError) {
          console.log(`[handleSaveNote] Save successful (could not parse response)`);
        }
      } else {
        const errorText = await response.text().catch(() => '');
        let errorData: { message?: string; error?: string } = {};
        try {
          errorData = errorText ? JSON.parse(errorText) : {};
        } catch {
          // Not JSON, use as plain text
        }
        const errorMessage = errorData.message || errorData.error || errorText || `Failed to save note: ${response.status} ${response.statusText}`;
        console.error(`[handleSaveNote] Error saving note (${response.status}):`, errorMessage);
        throw new Error(errorMessage);
      }
    } catch (error) {
      console.error('Error saving note:', error);
    } finally {
      setIsSaving(false);
    }
  };

  // Handle panel resizing
  const handleNavResize = (e: MouseEvent) => {
    if (!isDraggingNav) return;
    const newWidth = e.clientX;
    if (newWidth >= 48 && newWidth <= 400) {
      setNavWidth(newWidth);
    }
  };

  const handleNotesResize = (e: MouseEvent) => {
    if (!isDraggingNotes) return;
    const newWidth = e.clientX - navWidth - 2; // 2px for the resizer
    if (newWidth >= 200) {
      setNotesWidth(newWidth);
    }
  };

  const handleNoteSelect = (note: Note) => {
    setSelectedNote(note);
    if (isMobile) {
      setShowNotes(false);
    }
  };

  const handleNoteSave = async (note: Note) => {
    try {
      const endpoint = '/api/storage/files';
      const method = note.id ? 'PUT' : 'POST';
      
      const response = await fetch(endpoint, {
        method,
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          id: note.id,
          title: note.title,
          content: note.content,
          folder: selectedFolder.toLowerCase()
        }),
      });

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Failed to save note: ${errorText}`);
      }

      // After successful save, refresh the notes list
      const notesResponse = await fetch(`/api/storage/files?folder=${selectedFolder.toLowerCase()}`);
      if (notesResponse.ok) {
        const updatedNotes = await notesResponse.json();
        setNotes(updatedNotes);
      }
    } catch (error) {
      console.error('Error saving note:', error);
      throw error; // Re-throw pour permettre la gestion d'erreur en amont
    }
  };

  const handleFolderSelect = async (folder: string) => {
    console.log('Selected folder:', folder);
    setSelectedFolder(folder);
    setLayoutMode("item-selection");
    
    // Reset selected note, contact, and mission when changing folders
    setSelectedNote(null);
    setSelectedContact(null);
    setSelectedMission(null);
    setSelectedMissionFile(null);
    
    // For Missions, don't create folder structure
    if (folder === 'Missions') {
      return;
    }
    
    // Ensure folder exists in storage before fetching
    try {
      // Create the folder if it doesn't exist
      const lowerFolder = folder.toLowerCase();
      console.log(`Ensuring folder exists: ${lowerFolder}`);
      
      const response = await fetch(`/api/storage/init/folder`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ folder: lowerFolder })
      });
      
      if (!response.ok) {
        console.warn(`Failed to create folder ${lowerFolder}: ${await response.text()}`);
      }
    } catch (error) {
      console.error('Error creating folder:', error);
    }
  };

  const handleContactSelect = (contact: Contact) => {
    setSelectedContact(contact);
    if (isMobile) {
      setShowNotes(false);
    }
  };

  const handleMissionSelect = async (mission: { id: string; name: string }) => {
    // Fetch full mission details including creator and missionUsers
    try {
      const response = await fetch(`/api/missions/${mission.id}`);
      if (response.ok) {
        const missionData = await response.json();
        setSelectedMission({
          id: missionData.id,
          name: missionData.name,
          creatorId: missionData.creatorId || missionData.creator?.id,
          isClosed: missionData.isClosed || false,
          missionUsers: missionData.missionUsers || []
        });
      } else {
        // Fallback to basic mission data
        setSelectedMission(mission);
      }
    } catch (error) {
      console.error('Error fetching mission details:', error);
      setSelectedMission(mission);
    }
    setSelectedMissionFile(null);
  };

  const handleMissionFileSelect = async (file: { key: string; name: string; path: string }) => {
    if (!selectedMission) return;
    
    // Check file extension to determine if it's a text file
    const fileName = file.name.toLowerCase();
    const textExtensions = ['.md', '.txt', '.json', '.yaml', '.yml', '.csv', '.log', '.conf', '.config', '.ini', '.env'];
    const isTextFile = textExtensions.some(ext => fileName.endsWith(ext));
    
    // For binary files (PDF, images, etc.), download them instead
    if (!isTextFile) {
      try {
        // Get the file URL for download
        const fileUrl = `/api/missions/image/${file.key}`;
        // Open in new tab or download
        window.open(fileUrl, '_blank');
        return;
      } catch (error) {
        console.error('Error opening file:', error);
        return;
      }
    }
    
    // For text files, fetch and open in editor
    try {
      const response = await fetch(`/api/missions/${selectedMission.id}/files`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ key: file.key })
      });
      
      if (response.ok) {
        const data = await response.json();
        setSelectedMissionFile({
          key: file.key,
          content: data.content || ''
        });
      }
    } catch (error) {
      console.error('Error fetching mission file content:', error);
    }
  };

  const handleMissionFileSave = async (content: string) => {
    if (!selectedMission || !selectedMissionFile) return;
    
    try {
      const response = await fetch(`/api/missions/${selectedMission.id}/files`, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          key: selectedMissionFile.key,
          content
        })
      });
      
      if (!response.ok) {
        throw new Error('Failed to save file');
      }
    } catch (error) {
      console.error('Error saving mission file:', error);
      throw error;
    }
  };

  const handleNewNote = async () => {
    // For Diary and Health folders, check if a note exists for today
    if (selectedFolder === 'Diary' || selectedFolder === 'Health') {
      const today = new Date();
      const dateStr = format(today, 'yyyy-MM-dd'); // For filename matching
      const dateTitle = format(today, 'd MMMM yyyy', { locale: fr }); // For display: "16 janvier 2026"
      
      // Refresh notes list first to ensure we have the latest data
      await fetchNotes(true);
      
      // Check if a note with this date already exists
      // We check both the date string (YYYY-MM-DD) and the formatted title
      const existingNote = notes.find(note => {
        const title = note.title || '';
        const noteId = note.id || '';
        // Check multiple patterns to find the existing note
        return title === dateTitle || 
               title === dateStr ||
               title.startsWith(dateStr) || 
               title.startsWith(dateTitle) ||
               noteId.includes(dateStr) ||
               noteId.includes(dateTitle.replace(/\s/g, '_')) ||
               noteId.includes(dateTitle.replace(/\s/g, '-'));
      });
      
      if (existingNote) {
        // Open the existing note for today
        console.log(`[handleNewNote] Found existing note for today: ${existingNote.title}, id: ${existingNote.id}`);
        handleNoteSelect(existingNote);
        return;
      }
      
      // Create a new note with today's date as title (formatted for display)
      // Set the id to the expected fileKey so handleSaveNote will use it
      const expectedFileKey = `user-${session?.user?.id}/${selectedFolder.toLowerCase()}/${dateTitle.replace(/\s/g, '_')}.md`;
      const newNote: Note = {
        id: expectedFileKey, // Pre-set the id to the expected fileKey
        title: dateTitle, // Use formatted date for display: "16 janvier 2026"
        content: '',
        lastModified: today.toISOString(),
        type: 'file',
        mime: 'text/markdown',
        etag: ''
      };
      
      console.log(`[handleNewNote] Creating new note for today with id: ${expectedFileKey}`);
      setSelectedNote(newNote);
      if (isMobile) {
        setShowNotes(false);
      }
    } else {
      // For other folders (Bloc-notes)
      console.log(`[handleNewNote] BLOC-NOTES: Starting new note creation`);
      console.log(`[handleNewNote] BLOC-NOTES: Current notes count: ${notes.length}`);
      console.log(`[handleNewNote] BLOC-NOTES: Current notes:`, notes.map(n => ({ id: n.id, title: n.title })));
      
      // Refresh notes list first
      console.log(`[handleNewNote] BLOC-NOTES: Refreshing notes list...`);
      await fetchNotes(true);
      console.log(`[handleNewNote] BLOC-NOTES: After refresh, notes count: ${notes.length}`);
      console.log(`[handleNewNote] BLOC-NOTES: After refresh, notes:`, notes.map(n => ({ id: n.id, title: n.title })));
      
      // Check if "Untitled" already exists
      const untitledNote = notes.find(note => {
        const title = note.title || '';
        const isUntitled = title === 'Untitled' || title === '' || title.trim() === '';
        if (isUntitled) {
          console.log(`[handleNewNote] BLOC-NOTES: Found potential Untitled note:`, { id: note.id, title: note.title });
        }
        return isUntitled;
      });
      
      if (untitledNote) {
        // Open the existing untitled note
        console.log(`[handleNewNote] BLOC-NOTES: Found existing untitled note, opening it:`, { id: untitledNote.id, title: untitledNote.title });
        handleNoteSelect(untitledNote);
        return;
      }
      
      // Create a blank note with a temporary unique id to track it
      // This id will be used in handleSaveNote to check for duplicates
      const tempId = `temp-${Date.now()}`;
      console.log(`[handleNewNote] BLOC-NOTES: No existing Untitled note found, creating new note with temp id: ${tempId}`);
      const newNote = {
        id: tempId, // Temporary id to track this new note
        title: '',
        content: '',
        lastModified: new Date().toISOString(),
        type: 'file',
        mime: 'text/markdown',
        etag: ''
      };
      console.log(`[handleNewNote] BLOC-NOTES: Setting selectedNote:`, newNote);
      setSelectedNote(newNote);
      if (isMobile) {
        setShowNotes(false);
      }
    }
  };

  const handleDeleteNote = async (note: Note) => {
    try {
      const response = await fetch(`/api/storage/files?id=${encodeURIComponent(note.id)}`, {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
        },
      });

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Failed to delete note: ${errorText}`);
      }

      // Invalidate cache for this folder
      if (session?.user?.id) {
        invalidateFolderCache(session.user.id, selectedFolder);
      }

      // Refresh the notes list using fetchNotes to ensure proper mapping
      // This ensures titles are correctly formatted for all folders
      await fetchNotes(true);

      // If the deleted note was selected, clear the selection
      if (selectedNote?.id === note.id) {
        setSelectedNote(null);
      }
    } catch (error) {
      console.error('Error deleting note:', error);
      throw error; // Re-throw pour permettre la gestion d'erreur en amont
    }
  };

  const handleContactSave = async (contact: Contact) => {
    if (!session?.user?.id) return;

    try {
      setIsLoading(true);
      
      // Use S3 path structure: user-{userId}/contacts/{filename}.vcf
      const vcfFile = 'Allemanique.vcf';
      const s3Key = `user-${session.user.id}/contacts/${vcfFile}`;

      let vcfContent = '';
      let existingContacts: string[] = [];

      try {
        // Try to get existing contacts from the VCF file
        const response = await fetch(`/api/storage/files/content?path=${encodeURIComponent(s3Key)}`);
        if (response.ok) {
          const { content } = await response.json();
          // Split the content into individual vCards
          existingContacts = content.split('BEGIN:VCARD')
            .filter((section: string) => section.trim())
            .map((section: string) => 'BEGIN:VCARD' + section.trim());
        }
      } catch (error) {
        // If the file doesn't exist, we'll create it with just the new contact
        console.log('No existing VCF file found, will create a new one');
      }
      
      // Update or add the contact
      let updatedVcards: string[] = [];
      let contactUpdated = false;
      
      for (const vcard of existingContacts) {
        const parsed = parseVCard(vcard);
        if (parsed.uid?.[0]?.value === contact.id) {
          // Replace the existing contact
          const newVcard = [
            'BEGIN:VCARD',
            'VERSION:3.0',
            `UID:${contact.id}`,
            `FN:${contact.fullName || ''}`,
            ...(contact.email ? [`EMAIL;TYPE=INTERNET:${contact.email}`] : []),
            ...(contact.phone ? [`TEL;TYPE=CELL:${contact.phone}`] : []),
            ...(contact.organization ? [`ORG:${contact.organization}`] : []),
            ...(contact.address ? [`ADR:${contact.address}`] : []),
            ...(contact.notes ? [`NOTE:${contact.notes}`] : []),
            'END:VCARD'
          ].join('\n');
          updatedVcards.push(newVcard);
          contactUpdated = true;
        } else {
          // Keep the existing contact
          updatedVcards.push(vcard);
        }
      }
      
      // If contact wasn't found, add it as new
      if (!contactUpdated) {
        const newVcard = [
          'BEGIN:VCARD',
          'VERSION:3.0',
          `UID:${contact.id}`,
          `FN:${contact.fullName || ''}`,
          ...(contact.email ? [`EMAIL;TYPE=INTERNET:${contact.email}`] : []),
          ...(contact.phone ? [`TEL;TYPE=CELL:${contact.phone}`] : []),
          ...(contact.organization ? [`ORG:${contact.organization}`] : []),
          ...(contact.address ? [`ADR:${contact.address}`] : []),
          ...(contact.notes ? [`NOTE:${contact.notes}`] : []),
          'END:VCARD'
        ].join('\n');
        updatedVcards.push(newVcard);
      }
      
      // Join all vCards back together with proper spacing
      vcfContent = updatedVcards.join('\n\n');
      
      // Save the updated VCF file using S3 storage API
      const saveResponse = await fetch('/api/storage/files', {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          id: s3Key,
          title: vcfFile,
          content: vcfContent,
          folder: 'contacts',
          mime: 'text/vcard'
        }),
      });

      if (!saveResponse.ok) {
        const errorText = await saveResponse.text();
        throw new Error(`Failed to save contact: ${errorText}`);
      }

      // Refresh the contacts list
      await fetchContacts(selectedFolder);
      
      // Update the selected contact if it was edited
      if (contactUpdated) {
        setSelectedContact(contact);
      }
    } catch (error) {
      console.error('Error saving contact:', error);
      throw error; // Re-throw pour permettre la gestion d'erreur en amont
    } finally {
      setIsLoading(false);
    }
  };

  const handleContactDelete = async (contact: Contact) => {
    if (!confirm('Êtes-vous sûr de vouloir supprimer ce contact ?')) {
      return;
    }

    if (!session?.user?.id) {
      console.error('No user session available');
      return;
    }

    try {
      setIsLoading(true);
      
      // Use S3 path structure: user-{userId}/contacts/{filename}.vcf
      const vcfFile = contact.group ? `${contact.group}.vcf` : 'Allemanique.vcf';
      const s3Key = `user-${session.user.id}/contacts/${vcfFile}`;

      // Get existing contacts from the VCF file
      const response = await fetch(`/api/storage/files/content?path=${encodeURIComponent(s3Key)}`);
      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Failed to fetch contacts: ${errorText}`);
      }
      
      const { content } = await response.json();
      
      // Split the content into individual vCards and filter out the one to delete
      const vcards = content.split('BEGIN:VCARD').filter((section: string) => section.trim());
      const updatedVcards = vcards.filter((section: string) => {
        const vcard = parseVCard('BEGIN:VCARD' + section);
        return vcard.uid?.[0]?.value !== contact.id;
      });
      
      // Join the remaining vCards back together
      const vcfContent = updatedVcards.map((section: string) => 'BEGIN:VCARD' + section).join('\n');
      
      // Save the updated VCF file using S3 storage API
      const saveResponse = await fetch('/api/storage/files', {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          id: s3Key,
          title: vcfFile,
          content: vcfContent,
          folder: 'contacts',
          mime: 'text/vcard'
        }),
      });

      if (!saveResponse.ok) {
        const errorText = await saveResponse.text();
        throw new Error(`Failed to delete contact: ${errorText}`);
      }

      // Clear selected contact and refresh list
      setSelectedContact(null);
      await fetchContacts(selectedFolder);
    } catch (error) {
      console.error('Error deleting contact:', error);
      throw error; // Re-throw pour permettre la gestion d'erreur en amont
    } finally {
      setIsLoading(false);
    }
  };

  const generateVCardContent = (contact: Contact): string => {
    const vcard = {
      version: '3.0',
      uid: contact.id,
      fn: contact.fullName,
      email: contact.email ? [{ value: contact.email, type: 'INTERNET' }] : undefined,
      tel: contact.phone ? [{ value: contact.phone, type: 'CELL' }] : undefined,
      org: contact.organization ? [{ value: contact.organization }] : undefined,
      adr: contact.address ? [{ value: contact.address }] : undefined,
      note: contact.notes ? [{ value: contact.notes }] : undefined,
      categories: contact.group ? [{ value: contact.group }] : undefined
    };

    return formatVCard(vcard);
  };

  if (isLoading) {
    return (
      <div className="flex h-screen items-center justify-center">
        <div className="h-32 w-32 animate-spin rounded-full border-t-2 border-b-2 border-gray-900"></div>
      </div>
    );
  }

  return (
    <main className="w-full h-screen bg-black">
      <div className="w-full h-full px-4 pt-12 pb-4">
        <div className="flex h-full bg-carnet-bg">
          {/* Navigation Panel */}
          {showNav && (
            <>
              <div className="flex-none" style={{ width: navWidth }}>
                <Navigation 
                  nextcloudFolders={nextcloudFolders} 
                  onFolderSelect={handleFolderSelect}
                />
              </div>
              <PanelResizer
                isDragging={isDraggingNav}
                onDragStart={() => setIsDraggingNav(true)}
                onDragEnd={() => setIsDraggingNav(false)}
                onDrag={handleNavResize}
              />
            </>
          )}

          {/* Notes/Contacts/Missions Panel */}
          {showNotes && (
            <>
              <div className="flex-1 overflow-hidden">
                {selectedFolder === 'Contacts' ? (
                  <>
                    {console.log(`[Render] Rendering ContactsView with ${contacts.length} contacts`, contacts)}
                    <ContactsView
                      contacts={contacts}
                      onContactSelect={handleContactSelect}
                      selectedContact={selectedContact}
                      loading={isLoadingContacts}
                    />
                  </>
                ) : selectedFolder === 'Missions' ? (
                  <MissionsView
                    onMissionSelect={handleMissionSelect}
                    selectedMissionId={selectedMission?.id}
                  />
                ) : (
                  <NotesView 
                    notes={notes}
                    loading={isLoadingNotes}
                    onNoteSelect={handleNoteSelect} 
                    currentFolder={selectedFolder}
                    onNewNote={handleNewNote}
                    onDeleteNote={handleDeleteNote}
                    onRefresh={() => {
                      // Force refresh by invalidating cache and fetching fresh data
                      if (session?.user?.id) {
                        invalidateFolderCache(session.user.id, selectedFolder);
                      }
                      fetchNotes(true);
                    }}
                  />
                )}
              </div>

              {/* Notes Resizer */}
              <PanelResizer
                isDragging={isDraggingNotes}
                onDragStart={() => setIsDraggingNotes(true)}
                onDragEnd={() => setIsDraggingNotes(false)}
                onDrag={handleNotesResize}
              />
            </>
          )}

          {/* Editor Panel */}
          <div className="flex-1 overflow-hidden">
            {selectedFolder === 'Contacts' || selectedFolder.endsWith('.vcf') ? (
              <ContactDetails 
                contact={selectedContact} 
                onSave={handleContactSave}
                onDelete={handleContactDelete}
              />
            ) : selectedFolder === 'Missions' ? (
              selectedMission && session?.user?.id ? (
                selectedMissionFile ? (
                  <Editor
                    note={{
                      id: selectedMissionFile.key,
                      title: selectedMissionFile.key.split('/').pop() || 'Fichier',
                      content: selectedMissionFile.content,
                      lastModified: new Date().toISOString(),
                      type: 'file',
                      mime: 'text/plain',
                      etag: ''
                    }}
                    onSave={async (note) => {
                      await handleMissionFileSave(note.content);
                    }}
                    currentFolder="Missions"
                  />
                ) : (
                  <MissionFilesManager
                    mission={{
                      id: selectedMission.id,
                      name: selectedMission.name,
                      creatorId: selectedMission.creatorId || '',
                      isClosed: selectedMission.isClosed || false,
                      missionUsers: selectedMission.missionUsers || []
                    }}
                    currentUserId={session.user.id}
                    currentPath="attachments"
                    onFileSelect={handleMissionFileSelect}
                    selectedFileKey={undefined}
                  />
                )
              ) : (
                <div className="flex items-center justify-center h-full">
                  <div className="text-center">
                    <p className="text-carnet-text-muted">Sélectionnez une mission</p>
                  </div>
                </div>
              )
            ) : (
              <Editor 
                note={selectedNote} 
                onSave={handleSaveNote}
                currentFolder={selectedFolder}
                onRefresh={() => {
                  // Refresh the notes list
                  fetchNotes();
                }}
              />
            )}
          </div>

          {/* Mobile Navigation Toggle */}
          {isMobile && (
            <button
              onClick={() => setShowNav(!showNav)}
              className="fixed bottom-4 right-4 bg-primary text-white p-3 rounded-full shadow-lg"
            >
              {showNav ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}
            </button>
          )}
        </div>
      </div>
    </main>
  );
}