ok im coding an app with an messsage app and an storing system like google drive i got many bug and i think backend frontend connection can you help me to patch the connection and can you rework the drive pls this is my code :

# app.py
from fastapi import FastAPI, Depends, HTTPException, status, UploadFile, File as FastAPIFile, Body, Form, Path, Query
from fastapi.middleware.cors import CORSMiddleware
from pymongo import MongoClient, ASCENDING, TEXT
from bson.objectid import ObjectId
import bcrypt
import cloudinary
import cloudinary.uploader
from dotenv import load_dotenv
from models import *
from authentication import get_current_user, authenticate_user, create_access_token, get_user
from config import *
from database import get_db, users_collection, conversations_collection, files_collection, folders_collection

# Load environment variables
load_dotenv()

# Configure Cloudinary
cloudinary.config(
    cloud_name=CLOUD_NAME,
    api_key=API_KEY_CLOUD,
    api_secret=API_SECRET_CLOUD,
    secure=True,
)

app = FastAPI()

# CORS Configuration
origins = [
    "http://localhost:3000",
    "https://frontend-lut9.onrender.com",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class BioUpdate(BaseModel):
    bio: str

@app.post("/signup", response_model=User)
def signup(user: UserCreate):
    # Check if user already exists
    if users_collection.find_one({"name": user.name}):
        raise HTTPException(status_code=400, detail="Username already exists.")

    # Hash password
    hashed_password = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt())

    # Default avatars
    random_pp = [
        "https://res.cloudinary.com/dcigc9jyw/raw/upload/v1732209655/avatar/e8kenkyye3vxpleuntso.jpg",
        "https://res.cloudinary.com/dcigc9jyw/raw/upload/v1732209837/avatar/ehgaeiwnr9eslhinl8x9.jpg",
        "https://res.cloudinary.com/dcigc9jyw/raw/upload/v1732210048/avatar/vfx6y1r9dngczafln2st.jpg"
    ]
    random_number = random.randint(0, len(random_pp) - 1)

    # Prepare user document
    user_doc = {
        "name": user.name,
        "password": hashed_password.decode('utf-8'),
        "bio": user.bio or "",
        "avatar_url": random_pp[random_number],
        "folders": {}
    }

    # Insert user
    result = users_collection.insert_one(user_doc)

    return User(
        id=str(result.inserted_id),
        name=user.name,
        bio=user.bio or "",
        avatar_url=random_pp[random_number],
        folders=user_doc["folders"]
    )

# Endpoint pour la connexion
@app.post("/login")
def login(form_data: UserCreate):
    user = authenticate_user(users_collection, form_data.name, form_data.password)
    if not user:
        raise HTTPException(status_code=400, detail="Nom d'utilisateur ou mot de passe incorrect")
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.name}, expires_delta=access_token_expires
    )
    return {
        "access_token": access_token,
        "token_type": "bearer"
    }

# Updated create_folder endpoint to handle nested folders
@app.post("/folders")
def create_folder(
    folder_name: str = Body(...),
    parent_folder_id: Optional[str] = Body(None),
    current_user: UserInDB = Depends(get_current_user),
):
    # Check if a folder with the same name exists under the same parent for this user
    existing_folder = folders_collection.find_one({
        "owner": current_user.name,
        "name": folder_name,
        "parent_folder": parent_folder_id
    })
    if existing_folder:
        raise HTTPException(status_code=400, detail="Folder with this name already exists in this location.")

    # Ensure the folder_name is not empty and is a valid string
    if not folder_name.strip():
        raise HTTPException(status_code=400, detail="Folder name cannot be empty.")

    folder = FolderModel(
        id=str(uuid.uuid4()),
        owner=current_user.name,
        name=folder_name,
        parent_folder=parent_folder_id,  # Store parent folder ID as string
        created_at=datetime.utcnow(),
    )

    folders_collection.insert_one(folder.dict(exclude_unset=True))
    return {"message": "Folder created successfully", "folder_id": folder.id}

# Add these improvements to your file upload endpoint
@app.post("/files")
async def upload_file(
    file: UploadFile = FastAPIFile(...),
    parent_folder_id: Optional[str] = Form(None),
    current_user: UserInDB = Depends(get_current_user)
):
    # 1. Add file type validation
    ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.pdf', '.doc', '.docx'}
    file_extension = os.path.splitext(file.filename)[1].lower()
    if file_extension not in ALLOWED_EXTENSIONS:
        raise HTTPException(status_code=400, detail="File type not allowed")

    # 2. Implement better file size validation
    MAX_FILE_SIZE = 50 * 1024 * 1024  # 50MB
    file_size = 0
    chunk_size = 1024 * 1024  # 1MB chunks

    # Stream the file to check size
    while chunk := await file.read(chunk_size):
        file_size += len(chunk)
        if file_size > MAX_FILE_SIZE:
            raise HTTPException(status_code=400, detail="File too large")

    await file.seek(0)  # Reset file pointer

    # Upload to Cloudinary
    result = cloudinary.uploader.upload(file.file, folder=parent_folder_id)
    file_url = result['secure_url']

    # Save file metadata to database
    file_doc = {
        "owner": current_user.name,
        "name": file.filename,
        "url": file_url,
        "parent_folder": parent_folder_id,
        "shared_with": [],
        "created_at": datetime.utcnow(),
    }
    files_collection.insert_one(file_doc)

    return {"message": "File uploaded successfully", "url": file_url}

@app.get("/folders/{folder_id}/contents")
def get_folder_contents(
    folder_id: str = Path(...),  # Use Path to handle folder_id
    current_user: UserInDB = Depends(get_current_user),
    folder_id_none: Optional[str] = Query(None),  # Use Query to handle optional folder_id
):
    # Convert folder_id to ObjectId if it is provided, otherwise use None
    folder_id_obj = ObjectId(folder_id) if folder_id_none is None else None

    # Verify folder ownership or access (if not root folder)
    if folder_id_obj:  # Only check ownership if folder_id is provided (not root)
        folder = folders_collection.find_one({"_id": folder_id_obj})
        if not folder:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Folder not found")
        if current_user.name != folder["owner"] and current_user.name not in folder.get("shared_with", []):
            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied")

    # Get subfolders
    subfolders = list(folders_collection.find({
        "parent_folder": folder_id if folder_id_none else None, # Use folder_id directly, no need to convert to ObjectId
        "$or": [
            {"owner": current_user.name},
            {"shared_with": current_user.name}
        ]
    }))

    # Get files
    files = list(files_collection.find({
        "parent_folder": folder_id if folder_id_none else None, # Use folder_id directly, no need to convert to ObjectId
        "$or": [
            {"owner": current_user.name},
            {"shared_with": current_user.name}
        ]
    }))

    return {
        "folders": [{"id": str(folder["_id"]), "name": folder["name"]} for folder in subfolders],
        "files": [{"id": str(file["_id"]), "name": file["name"], "url": file["url"]} for file in files],
    }

# Delete File
@app.delete("/files/{file_id}")
def delete_file(file_id: str, current_user: UserInDB = Depends(get_current_user)):
    file = files_collection.find_one({"_id": ObjectId(file_id)})
    if not file:
        raise HTTPException(status_code=404, detail="File not found")
    if current_user.name != file["owner"]:
        raise HTTPException(status_code=403, detail="Access denied")

    # Delete file from Cloudinary
    try:
        public_id = file['url'].split('/')[-1].split('.')[0]
        cloudinary.uploader.destroy(public_id)
    except Exception as e:
        logging.error(f"Cloudinary deletion error: {e}")
        raise HTTPException(status_code=500, detail="Error deleting file from Cloudinary.")

    files_collection.delete_one({"_id": ObjectId(file_id)})
    return {"message": "File deleted successfully"}

# Delete Folder (recursive)
@app.delete("/folders/{folder_id}")
def delete_folder(folder_id: str, current_user: UserInDB = Depends(get_current_user)):
    folder = folders_collection.find_one({"_id": ObjectId(folder_id)})
    if not folder:
        raise HTTPException(status_code=404, detail="Folder not found")
    if current_user.name != folder["owner"]:
        raise HTTPException(status_code=403, detail="Access denied")

    # Recursive deletion
    def delete_folder_recursive(f_id):
        # Delete all subfolders
        subfolders = list(folders_collection.find({"parent_folder": f_id}))
        for subfolder in subfolders:
            delete_folder_recursive(subfolder["_id"])
        # Delete all files in this folder
        files_collection.delete_many({"parent_folder": f_id})
        # Delete the folder itself
        folders_collection.delete_one({"_id": f_id})

    delete_folder_recursive(ObjectId(folder_id))
    return {"message": "Folder and its contents deleted successfully"}

# Rename File
@app.put("/files/{file_id}/rename")
def rename_file(
    file_id: str,
    new_name: str = Body(..., embed=True),
    current_user: UserInDB = Depends(get_current_user)
):
    file = files_collection.find_one({"_id": ObjectId(file_id)})
    if not file:
        raise HTTPException(status_code=404, detail="File not found")
    if current_user.name != file["owner"]:
        raise HTTPException(status_code=403, detail="Access denied")

    # Check for name conflicts
    existing_file = files_collection.find_one({
        "owner": current_user.name,
        "name": new_name,
        "parent_folder": file["parent_folder"]
    })
    if existing_file:
        raise HTTPException(status_code=400, detail="A file with this name already exists in this folder.")

    files_collection.update_one(
        {"_id": ObjectId(file_id)},
        {"$set": {"name": new_name}}
    )
    return {"message": "File renamed successfully"}

# Rename Folder
@app.put("/folders/{folder_id}/rename")
def rename_folder(
    folder_id: str,
    new_name: str = Body(..., embed=True),
    current_user: UserInDB = Depends(get_current_user)
):
    folder = folders_collection.find_one({"_id": ObjectId(folder_id)})
    if not folder:
        raise HTTPException(status_code=404, detail="Folder not found")
    if current_user.name != folder["owner"]:
        raise HTTPException(status_code=403, detail="Access denied")

    # Check for name conflicts
    existing_folder = folders_collection.find_one({
        "owner": current_user.name,
        "name": new_name,
        "parent_folder": folder["parent_folder"]
    })
    if existing_folder:
        raise HTTPException(status_code=400, detail="A folder with this name already exists in this location.")

    folders_collection.update_one(
        {"_id": ObjectId(folder_id)},
        {"$set": {"name": new_name}}
    )
    return {"message": "Folder renamed successfully"}

# Share File
@app.post("/files/{file_id}/share")
def share_file(
    file_id: str,
    shared_user_name: str = Body(..., embed=True),
    current_user: UserInDB = Depends(get_current_user)
):
    file = files_collection.find_one({"_id": ObjectId(file_id)})
    if not file:
        raise HTTPException(status_code=404, detail="File not found")
    if current_user.name != file["owner"]:
        raise HTTPException(status_code=403, detail="Access denied")

    shared_user = users_collection.find_one({"name": shared_user_name})
    if not shared_user:
        raise HTTPException(status_code=404, detail="User to share with not found")

    if shared_user_name in file.get("shared_with", []):
        raise HTTPException(status_code=400, detail="File already shared with this user")

    files_collection.update_one(
        {"_id": ObjectId(file_id)},
        {"$push": {"shared_with": shared_user_name}}
    )
    return {"message": f"File shared with {shared_user_name}"}

# Share Folder
@app.post("/folders/{folder_id}/share")
def share_folder(
    folder_id: str,
    shared_user_name: str = Body(..., embed=True),
    current_user: UserInDB = Depends(get_current_user)
):
    folder = folders_collection.find_one({"_id": ObjectId(folder_id)})
    if not folder:
        raise HTTPException(status_code=404, detail="Folder not found")
    if current_user.name != folder["owner"]:
        raise HTTPException(status_code=403, detail="Access denied")

    shared_user = users_collection.find_one({"name": shared_user_name})
    if not shared_user:
        raise HTTPException(status_code=404, detail="User to share with not found")

    if shared_user_name in folder.get("shared_with", []):
        raise HTTPException(status_code=400, detail="Folder already shared with this user")

    # Recursive sharing
    def share_folder_recursive(f_id, user_name):
        # Share the folder
        folders_collection.update_one(
            {"_id": f_id},
            {"$push": {"shared_with": user_name}}
        )
        # Share all files in this folder
        files_collection.update_many(
            {"parent_folder": f_id},
            {"$push": {"shared_with": user_name}}
        )
        # Share subfolders
        subfolders = list(folders_collection.find({"parent_folder": f_id}))
        for subfolder in subfolders:
            share_folder_recursive(subfolder["_id"], user_name)

    share_folder_recursive(ObjectId(folder_id), shared_user_name)
    return {"message": f"Folder and its contents shared with {shared_user_name}"}

@app.get("/showfolder", response_model=User)
def read_current_user(current_user: UserInDB = Depends(get_current_user)):
    user = users_collection.find_one({"name": current_user.name})
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return User(
        id=str(user["_id"]),
        name=user["name"],
        bio=user.get("bio", ""),
        avatar_url=user.get("avatar_url")
    )

@app.get("/users/me", response_model=User)
def read_current_user(current_user: UserInDB = Depends(get_current_user)):
    user = users_collection.find_one({"name": current_user.name})
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return User(
        id=str(user["_id"]),
        name=user["name"],
        bio=user.get("bio", ""),
        avatar_url=user.get("avatar_url")
    )

@app.put("/users/me/bio", response_model=UserBase)
def update_bio(bio_update: BioUpdate, current_user: UserInDB = Depends(get_current_user)):
    users_collection.update_one(
        {"name": current_user.name},
        {"$set": {"bio": bio_update.bio}}
    )
    updated_user = users_collection.find_one({"name": current_user.name})
    if not updated_user:
        raise HTTPException(status_code=404, detail="User not found")
    return UserBase(
        name=updated_user["name"],
        bio=updated_user.get("bio", ""),
        avatar_url=updated_user.get("avatar_url")
    )

# Endpoint pour obtenir le profil d'un utilisateur par nom d'utilisateur
@app.get("/users/{username}", response_model=UserBase)
def get_user_profile(username: str, current_user: UserInDB = Depends(get_current_user)):
    user = users_collection.find_one({"name": username})
    if not user:
        raise HTTPException(status_code=404, detail="Utilisateur non trouvé")
    return UserBase(
        name=user["name"],
        bio=user.get("bio", ""),
        avatar_url=user.get("avatar_url")  # Inclure avatar_url
    )

# Endpoint pour obtenir tous les utilisateurs
@app.get("/users", response_model=List[UserBase])
def get_all_users(current_user: UserInDB = Depends(get_current_user)):
    users = users_collection.find({})
    return [UserBase(name=user["name"], bio=user.get("bio", ""), avatar_url=user.get("avatar_url")) for user in users]

# Endpoint pour créer une conversation
@app.post("/conversations", response_model=Conversation)
def create_conversation(convo: ConversationCreate, current_user: UserInDB = Depends(get_current_user)):
    participants = convo.participants
    if current_user.name not in participants:
        participants.append(current_user.name)

    # Vérifier que les utilisateurs existent
    for name in participants:
        if not users_collection.find_one({"name": name}):
            raise HTTPException(status_code=404, detail=f"Utilisateur {name} non trouvé")

    # Si c'est une conversation privée sans nom, vérifier si elle existe déjà
    if len(participants) == 2 and not convo.name:
        existing_convo = conversations_collection.find_one({
            "participants": {"$all": participants},
            "name": {"$exists": False}
        })
        if existing_convo:
            raise HTTPException(status_code=400, detail="La conversation existe déjà")

    # Créer la conversation
    conversation_doc = {
        "participants": participants,
        "messages": [],
    }
    if convo.name:
        conversation_doc["name"] = convo.name

    result = conversations_collection.insert_one(conversation_doc)
    return Conversation(
        id=str(result.inserted_id),
        name=convo.name,
        participants=participants
    )

# Endpoint pour obtenir les conversations de l'utilisateur courant
@app.get("/conversations", response_model=List[Conversation])
def get_user_conversations(current_user: UserInDB = Depends(get_current_user)):
    conversations = conversations_collection.find({"participants": current_user.name})
    convo_list = []
    for convo in conversations:
        convo_list.append(Conversation(
            id=str(convo['_id']),
            name=convo.get("name"),
            participants=convo["participants"],
            messages=[]
        ))
    return convo_list

# Endpoint pour obtenir une conversation par ID
@app.get("/conversations/{conversation_id}", response_model=Conversation)
def get_conversation(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except:
        raise HTTPException(status_code=400, detail="ID de conversation invalide")
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation non trouvée")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Accès refusé")
    messages = [Message(**msg) for msg in conversation.get("messages", [])]
    return Conversation(
        id=str(conversation['_id']),
        name=conversation.get("name"),
        participants=conversation["participants"],
        messages=messages
    )

@app.post("/conversations/{conversation_id}/messages", response_model=Message)
def send_message(conversation_id: str, message_create: MessageCreate, current_user: UserInDB = Depends(get_current_user)):
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except:
        raise HTTPException(status_code=400, detail="ID de conversation invalide")
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation non trouvée")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Accès refusé")

    # Créer le message avec un ID unique
    message = Message(
        id=str(uuid.uuid4()),  # Générer un ID unique pour le message
        sender=current_user.name,
        content=message_create.content or "",
        timestamp=datetime.utcnow(),
        media=message_create.media or "",
        reactions={}
    )
    # Enregistrer le message dans la base de données
    message_doc = message.dict(exclude_unset=True)
    conversations_collection.update_one(
        {"_id": ObjectId(conversation_id)},
        {"$push": {"messages": message_doc}}
    )

    return message

@app.post("/conversations/{conversation_id}/messages/{message_id}/reactions", response_model=Message)
def add_reaction(conversation_id: str, message_id: str, reaction: str = Body(...), current_user: UserInDB = Depends(get_current_user)):
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except:
        raise HTTPException(status_code=400, detail="ID de conversation invalide")
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation non trouvée")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Accès refusé")

    # Trouver le message avec l'ID spécifié
    message = next((msg for msg in conversation["messages"] if str(msg["id"]) == message_id), None)
    if not message:
        raise HTTPException(status_code=404, detail="Message non trouvé")

    # Ajouter la réaction
    if reaction in message["reactions"]:
        message["reactions"][reaction] += 1
    else:
        message["reactions"][reaction] = 1

    # Mettre à jour la conversation dans la base de données
    conversations_collection.update_one(
        {"_id": ObjectId(conversation_id)},
        {"$set": {"messages": conversation["messages"]}}
    )

    return message

@app.get("/conversations/{conversation_id}/messages", response_model=List[Message])
def get_messages(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except:
        raise HTTPException(status_code=400, detail="ID de conversation invalide")
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation non trouvée")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Accès refusé")
    messages = [Message(**msg) for msg in conversation.get("messages", [])]
    return messages

@app.delete("/conversations/{conversation_id}")
def delete_conversation(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
    conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation non trouvée")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Accès refusé")

    conversations_collection.delete_one({"_id": ObjectId(conversation_id)})
    return {"detail": "Conversation supprimée"}

@app.post("/upload/avatar/", response_model=dict)
async def upload_avatar(file: UploadFile = FastAPIFile(...), current_user: UserInDB = Depends(get_current_user)):
    if not file.content_type.startswith('image/'):
        raise HTTPException(status_code=400, detail="Seuls les fichiers image sont autorisés.")

    # Vérifier la taille du fichier (limitée à 5MB)
    contents = await file.read()
    MAX_FILE_SIZE = 5 * 1024 * 1024  # 5 MB
    if len(contents) > MAX_FILE_SIZE:
        raise HTTPException(status_code=400, detail="La taille du fichier dépasse la limite de 5MB.")
    await file.seek(0)  # Réinitialiser le pointeur de fichier après la lecture

    # Enregistrer le fichier
    result = cloudinary.uploader.upload(file.file, folder="avatar", resource_type="raw")
    file_url = result["secure_url"]

    users_collection.update_one(
        {"name": current_user.name},
        {"$set": {"avatar_url": file_url}}
    )
    return {"avatar_url": file_url}


# authentication.py
from datetime import datetime, timedelta
from typing import Optional
import jwt
from jwt.exceptions import PyJWTError as JWTError
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from pymongo import MongoClient
from models import UserInDB
from config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
import bcrypt
import os
from database import get_db

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return bcrypt.checkpw(
        plain_password.encode('utf-8'),
        hashed_password.encode('utf-8')
    )

def get_user(db, username: str) -> Optional[UserInDB]:
    user = db.find_one({"name": username})
    if user:
        return UserInDB(
            name=user["name"],
            hashed_password=user["password"],
            avatar_url=user.get("avatar_url")
        )
    return None

def authenticate_user(db, username: str, password: str):
    user = get_user(db, username)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

async def get_current_user(token: str = Depends(oauth2_scheme), db=Depends(get_db)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception

        user = get_user(db["users"], username)
        if user is None:
            raise credentials_exception
        return user
    except JWTError:
        raise credentials_exception
# database.py
from pymongo import MongoClient, ASCENDING, TEXT
from config import MONGODB_URI

client = MongoClient(MONGODB_URI)
db = client["FIRSTSERv"]
users_collection = db["users"]
conversations_collection = db["conversations"]
files_collection = db["files"]
folders_collection = db["folders"]

# Créer des index si ils n'existent pas
users_collection.create_index([("name", ASCENDING)], unique=True)
conversations_collection.create_index([("participants", ASCENDING)])
conversations_collection.create_index([("messages.content", TEXT)])
files_collection.create_index([("owner", ASCENDING)])
folders_collection.create_index([("owner", ASCENDING)])

# file_service.py
from typing import Optional
import cloudinary.uploader
from fastapi import HTTPException
from models import *

class FileService:
    def __init__(self, db, cloudinary_config):
        self.db = db
        self.cloudinary_config = cloudinary_config

    async def upload_file(self, file: UploadFile, owner: str, parent_folder_id: Optional[str] = None):
        try:
            # Upload to Cloudinary with better error handling
            upload_result = await self.upload_to_cloudinary(file, parent_folder_id)

            # Save file metadata to database
            file_data = await self.save_file_metadata(
                owner=owner,
                filename=file.filename,
                url=upload_result['secure_url'],
                parent_folder_id=parent_folder_id
            )
            return file_data
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    async def upload_to_cloudinary(self, file: UploadFile, folder: Optional[str]):
        try:
            return cloudinary.uploader.upload(
                file.file,
                folder=folder,
                resource_type="auto",
                allowed_formats=["jpg", "png", "pdf", "doc", "docx"]
            )
        except Exception as e:
            raise HTTPException(status_code=500, detail="Cloudinary upload failed")

# config.py
import os
from dotenv import load_dotenv

load_dotenv()

# Database Configuration
MONGODB_URI = os.getenv("MONGODB_URI")

# JWT Configuration
SECRET_KEY = os.getenv("SECRET_KEY")
ALGORITHM = os.getenv("ALGORITHM", "HS256")
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", 30))

# Cloudinary Configuration
CLOUD_NAME = os.getenv("CLOUD_NAME")
API_KEY_CLOUD = os.getenv("API_KEY_CLOUD")
API_SECRET_CLOUD = os.getenv("API_SECRET_CLOUD")


# models.py
from pydantic import BaseModel, Field, ConfigDict
from typing import List, Optional, Dict, Any
from datetime import datetime
from uuid import UUID, uuid4

# User Models
class UserBase(BaseModel):
    name: str
    bio: Optional[str] = None
    avatar_url: Optional[str] = None
    model_config = ConfigDict(populate_by_name=True)

class UserCreate(UserBase):
    password: str

class UserInDB(UserBase):
    hashed_password: str

class User(UserBase):
    id: str

# Message Models
class MessageCreate(BaseModel):
    content: Optional[str] = None
    media: Optional[str] = None

class Message(BaseModel):
    id: str = Field(default_factory=lambda: str(uuid4()))
    sender: str
    content: str
    timestamp: datetime = Field(default_factory=datetime.utcnow)
    media: Optional[str] = None
    reactions: Dict[str, int] = {}
    model_config = ConfigDict(populate_by_name=True)

# Conversation Models
class ConversationCreate(BaseModel):
    participants: List[str]
    name: Optional[str] = None

class Conversation(BaseModel):
    id: str
    name: Optional[str] = None
    participants: List[str]
    messages: List[Message] = []
    model_config = ConfigDict(populate_by_name=True)

# File Models
class FileModel(BaseModel):
    id: str = Field(default_factory=lambda: str(uuid4()))
    owner: str
    name: str
    url: str
    parent_folder: Optional[str] = None  # ID of the parent folder
    shared_with: List[str] = []
    created_at: datetime = Field(default_factory=datetime.utcnow)

# Folder Models
class FolderModel(BaseModel):
    id: str = Field(default_factory=lambda: str(uuid4()))
    owner: str
    name: str
    parent_folder: Optional[str] = None  # ID of the parent folder
    shared_with: List[str] = []
    created_at: datetime = Field(default_factory=datetime.utcnow)

class FileCreate(BaseModel):
    folder_name: str
    file_name: str
    file: bytes

frontend :

// frontend/src/components/Auth/Login.js
import React, { useState, useContext } from 'react';
import { AuthContext } from '../../contexts/AuthContext';
import { useNavigate, Link } from 'react-router-dom';
import { motion } from 'framer-motion';
import styles from './Login.module.css';

function Login() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const { login } = useContext(AuthContext);
  const [error, setError] = useState('');
  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await login(username, password);
      navigate('/conversations');
    } catch (err) {
      const errorMessage = err.response?.data?.detail || "Incorrect username or password";
      setError(errorMessage);
    }
  };

  return (
    <motion.div
      className={styles.loginContainer}
      initial={{ opacity: 0, scale: 0.9 }}
      animate={{ opacity: 1, scale: 1 }}
      transition={{ duration: 0.5 }}
    >
      <div className={styles.loginBox}>
        <h2 className={styles.title}>Login</h2>
        <form onSubmit={handleSubmit} className={styles.form}>
          <div className={styles.inputGroup}>
            <label htmlFor="username">Username</label>
            <input
              id="username"
              type="text"
              value={username}
              onChange={(e) => setUsername(e.target.value)}
              required
              className={styles.input}
            />
          </div>
          <div className={styles.inputGroup}>
            <label htmlFor="password">Password</label>
            <input
              id="password"
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
              className={styles.input}
            />
          </div>
          <button type="submit" className={styles.submitButton}>
            Login
          </button>
        </form>
        {error && <p className={styles.error}>{error}</p>}
        <p className={styles.signupPrompt}>
          Don't have an account? <Link to="/signup">Sign up</Link>
        </p>
      </div>
    </motion.div>
  );
}

export default Login;
// frontend/src/components/Auth/Signup.js
import React, { useState, useContext, useEffect } from 'react';
import { AuthContext } from '../../contexts/AuthContext';
import { useNavigate, Link } from 'react-router-dom';
import styles from './Signup.module.css';

function Signup() {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const [step, setStep] = useState(1);
    const [isLoading, setIsLoading] = useState(false);
    const [isVisible, setIsVisible] = useState(false);
    const { signup } = useContext(AuthContext);
    const [error, setError] = useState('');
    const navigate = useNavigate();

    useEffect(() => {
        setIsVisible(true);
    }, []);

    const handleNextStep = (e) => {
        e.preventDefault();
        if (username.trim()) {
            setStep(2);
            setError('');
        } else {
            setError('Please enter a username');
        }
    };

    const handleBack = () => {
        setStep(1);
        setError('');
    };

    const handleSubmit = async (e) => {
        e.preventDefault();
        if (!password.trim()) {
            setError('Please enter a password');
            return;
        }

        setIsLoading(true);
        try {
            await signup(username, password);
            setIsLoading(false);
            navigate('/conversations');
        } catch (err) {
            const errorMessage = err.response?.data?.detail || "Error during signup";
            setError(errorMessage);
            setIsLoading(false);
        }
    };

    return (
        <div className={`${styles.container} ${isVisible ? styles.visible : ''}`}>
            <div className={styles.formWrapper}>
                <div className={styles.glowingBackground}></div>
                <div className={styles.stepIndicator}>
                    <div className={`${styles.step} ${step === 1 ? styles.active : styles.completed}`}>1</div>
                    <div className={styles.stepLine}></div>
                    <div className={`${styles.step} ${step === 2 ? styles.active : ''} ${step === 1 ? '' : styles.completed}`}>2</div>
                </div>

                <div className={styles.formContainer}>
                    <div className={`${styles.formSlide} ${step === 1 ? styles.activeSlide : ''}`}>
                        <form onSubmit={handleNextStep}>
                            <h2 className={styles.title}>Create Account</h2>
                            <p className={styles.subtitle}>Enter your username to get started</p>

                            <div className={styles.inputGroup}>
                                <input
                                    type="text"
                                    value={username}
                                    onChange={(e) => setUsername(e.target.value)}
                                    required
                                    className={styles.input}
                                    autoFocus
                                />
                                <span className={styles.highlight}></span>
                                <span className={styles.bar}></span>
                                <label className={styles.label}>Username</label>
                            </div>

                            {error && <div className={styles.error}>{error}</div>}

                            <button type="submit" className={styles.button}>
                                <span className={styles.buttonText}>Next</span>
                            </button>

                            <Link className={styles.link} to="/login">
                                Already have an account? Login
                            </Link>
                        </form>
                    </div>

                    <div className={`${styles.formSlide} ${step === 2 ? styles.activeSlide : ''}`}>
                        <form onSubmit={handleSubmit}>
                            <h2 className={styles.title}>Create Password</h2>
                            <p className={styles.subtitle}>Choose a strong password</p>

                            <div className={styles.usernameDisplay}>
                                <span className={styles.userIcon}>👤</span>
                                {username}
                                <button
                                    type="button"
                                    className={styles.editButton}
                                    onClick={handleBack}
                                >
                                    Edit
                                </button>
                            </div>

                            <div className={styles.inputGroup}>
                                <input
                                    type="password"
                                    value={password}
                                    onChange={(e) => setPassword(e.target.value)}
                                    required
                                    className={styles.input}
                                    autoFocus
                                />
                                <span className={styles.highlight}></span>
                                <span className={styles.bar}></span>
                                <label className={styles.label}>Password</label>
                            </div>

                            {error && <div className={styles.error}>{error}</div>}

                            <div className={styles.buttonGroup}>
                                <button
                                    type="submit"
                                    className={`${styles.button} ${isLoading ? styles.loading : ''}`}
                                    disabled={isLoading}
                                >
                                    <span className={styles.buttonText}>
                                        {isLoading ? 'Creating Account...' : 'Create Account'}
                                    </span>
                                </button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default Signup;

// frontend/src/components/Chat/Chat.js
import React, { useState, useEffect, useRef, useContext } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import axios from '../../utils/api';
import { AuthContext } from '../../contexts/AuthContext';
import { IoSend, IoSearch, IoAdd, IoImageOutline, IoCloseOutline } from 'react-icons/io5';
import styles from './Chat.module.css';
import CreateConversationModal from './CreateConversationModal';
import MessageReactions from './MessageReactions';

function Chat() {
  const { conversationId } = useParams();
  const { user, setUser } = useContext(AuthContext);
  const navigate = useNavigate();

  const [conversations, setConversations] = useState([]);
  const [currentConversation, setCurrentConversation] = useState(null);
  const [message, setMessage] = useState('');
  const [searchQuery, setSearchQuery] = useState('');
  const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
  const [selectedFile, setSelectedFile] = useState(null);
  const [previewImage, setPreviewImage] = useState(null);
  const messagesEndRef = useRef(null);
  const [usersMap, setUsersMap] = useState({});
  const [loadingConversations, setLoadingConversations] = useState(true);
  const [loadingMessages, setLoadingMessages] = useState(true);

  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const response = await axios.get('/users');
        const map = {};
        response.data.forEach(user => {
          map[user.name] = {
            avatar_url: user.avatar_url,
            name: user.name,
          };
        });
        setUsersMap(map);
      } catch (error) {
        console.error('Erreur lors de la récupération des utilisateurs :', error);
      }
    };

    fetchUsers();
  }, []);

  useEffect(() => {
    fetchConversations();
    const interval = setInterval(fetchConversations, 5000);
    return () => clearInterval(interval);
  }, []);

  useEffect(() => {
    if (conversationId) {
      fetchCurrentConversation();
      const interval = setInterval(fetchCurrentConversation, 3000);
      return () => clearInterval(interval);
    } else {
      setCurrentConversation(null);
    }
  }, [conversationId]);

  useEffect(() => {
    scrollToBottom();
  }, [currentConversation?.messages]);

  const fetchConversations = async () => {
    setLoadingConversations(true);
    try {
      const response = await axios.get('/conversations');
      setConversations(response.data);
    } catch (error) {
      console.error('Erreur lors de la récupération des conversations :', error);
    } finally {
      setLoadingConversations(false);
    }
  };

  const fetchCurrentConversation = async () => {
    if (!conversationId) return;

    setLoadingMessages(true);
    try {
      const response = await axios.get(`/conversations/${conversationId}`);
      setCurrentConversation(response.data);
    } catch (error) {
      console.error('Erreur lors de la récupération de la conversation :', error);
    } finally {
      setLoadingMessages(false);
    }
  };

  const handleSendMessage = async (e) => {
    e.preventDefault();
    if (!message.trim() && !selectedFile) return;

    let mediaUrl = null;
    if (selectedFile) {
      try {
        const formData = new FormData();
        formData.append('file', selectedFile);
        formData.append('parent_folder_id', currentConversation.id);

        const uploadResponse = await axios.post('/files', formData, {
          headers: { 'Content-Type': 'multipart/form-data' },
        });

        mediaUrl = uploadResponse.data.url;
        setSelectedFile(null);
        setPreviewImage(null);
      } catch (error) {
        console.error('Erreur lors du téléchargement du média :', error);
        alert('Échec du téléchargement du média.');
        return;
      }
    }

    const payload = {
      content: message.trim(),
      media: mediaUrl,
    };

    try {
      const response = await axios.post(`/conversations/${conversationId}/messages`, payload);
      const newMessage = response.data;

      setCurrentConversation(prev => ({
        ...prev,
        messages: [...prev.messages, newMessage],
      }));
      setMessage('');
    } catch (error) {
      console.error('Erreur lors de l\'envoi du message :', error);
    }
  };

  const handleAddReaction = async (messageId, reaction) => {
    if (!messageId) {
      console.error('ID du message non défini');
      return;
    }
    try {
      await axios.post(`/conversations/${conversationId}/messages/${messageId}/reactions`, { reaction });
      setCurrentConversation(prev => {
        const updatedMessages = prev.messages.map(msg => {
          if (msg.id === messageId) {
            return {
              ...msg,
              reactions: {
                ...msg.reactions,
                [reaction]: (msg.reactions[reaction] || 0) + 1,
              },
            };
          }
          return msg;
        });
        return { ...prev, messages: updatedMessages };
      });
    } catch (error) {
      console.error('Erreur lors de l\'ajout de la réaction :', error);
    }
  };

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  };

  const filteredConversations = conversations.filter(conv => {
    const conversationName = conv.name || conv.participants.join(', ');
    return conversationName.toLowerCase().includes(searchQuery.toLowerCase());
  });

  const openCreateModal = () => {
    setIsCreateModalOpen(true);
  };

  const closeCreateModal = () => {
    setIsCreateModalOpen(false);
  };

  const handleFileChange = (e) => {
    const file = e.target.files[0];
    if (file) {
      setSelectedFile(file);
      setPreviewImage(URL.createObjectURL(file));
    }
  };

  const removeSelectedFile = () => {
    setSelectedFile(null);
    setPreviewImage(null);
  };

  const handleProfileClick = (username) => {
    navigate(`/users/${username}`);
  };

  return (
    <div className={styles.container}>
      {/* Sidebar */}
      <aside className={styles.sidebar}>
        <div className={styles.sidebarHeader}>
          <div
            className={styles.userProfile}
            onClick={() => navigate('/profile')}
          >
            <div className={styles.userAvatar} onClick={() => handleProfileClick(user.name)}>
              {user.avatar_url ? (
                <img src={user.avatar_url} alt="Avatar" className={styles.avatarImage} onError={(e) => e.target.src='default_avatar.png'}/>
              ) : (
                <span>{user.name.charAt(0).toUpperCase()}</span>
              )}
            </div>
            <span className={styles.userName}>{user.name}</span>
          </div>
        </div>

        <div className={styles.searchContainer}>
          <input
            type="text"
            placeholder="Rechercher des conversations..."
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            className={styles.searchInput}
          />
          <IoSearch className={styles.searchIcon} />
        </div>

        <button onClick={openCreateModal} className={styles.newConversationButton}>
          <IoAdd /> Nouvelle Conversation
        </button>

        {loadingConversations ? (
          <div className={styles.loader}>Chargement des conversations...</div>
        ) : (
          <div className={styles.conversationsList}>
            {filteredConversations.map((conv) => (
              <div
                key={conv.id}
                className={`${styles.conversationItem} ${conv.id === conversationId ? styles.active : ''}`}
                onClick={() => navigate(`/chat/${conv.id}`)}
              >
                <div className={styles.conversationAvatar} onClick={() => handleProfileClick(conv.participants[0])}>
                  {usersMap[conv.participants[0]]?.avatar_url ? (
                    <img src={usersMap[conv.participants[0]].avatar_url} alt={`${usersMap[conv.participants[0]].name} Avatar`} onError={(e) => e.target.src='default_avatar.png'}/>
                  ) : (
                    <span>{usersMap[conv.participants[0]]?.name.charAt(0).toUpperCase()}</span>
                  )}
                </div>
                <div className={styles.conversationInfo}>
                  <span className={styles.conversationName}>
                    {usersMap[conv.participants[0]]?.name || conv.participants.join(', ')}
                  </span>
                  <span className={styles.conversationMessage}>
                    {conv.lastMessage?.content ? `${conv.lastMessage.content.substring(0, 30)}${conv.lastMessage.content.length > 30 ? '...' : ''}` : 'Aucun message'}
                  </span>
                </div>
              </div>
            ))}
          </div>
        )}
      </aside>

      {/* Main Chat Area */}
      <main className={styles.chatArea}>
        {currentConversation ? (
          loadingMessages ? (
            <div className={styles.loader}>Chargement des messages...</div>
          ) : (
            <>
              <div className={styles.chatHeader}>
                <div className={styles.chatHeaderInfo}>
                  <span className={styles.chatTitle}>
                    {currentConversation.name || currentConversation.participants.join(', ')}
                  </span>
                  <span className={styles.participantsCount}>
                    {currentConversation.participants.length} participants
                  </span>
                </div>
              </div>
              <div className={styles.messagesContainer}>
                {currentConversation.messages && currentConversation.messages.map((msg) => (
                  <div
                    key={msg.id}
                    className={`${styles.messageGroup} ${msg.sender === user.name ? styles.sent : styles.received}`}
                  >
                    <div className={styles.messagePicture} onClick={() => handleProfileClick(msg.sender)}>
                      {msg.sender === user.name ? (
                        user.avatar_url ? (
                          <img src={user.avatar_url} alt="Your Avatar" className={styles.avatarImage} onError={(e) => e.target.src='default_avatar.png'}/>
                        ) : (
                          <span>{user.name.charAt(0).toUpperCase()}</span>
                        )
                      ) : (
                        usersMap[msg.sender]?.avatar_url ? (
                          <img src={usersMap[msg.sender].avatar_url} alt={`${msg.sender} Avatar`} className={styles.avatarImage} onError={(e) => e.target.src='default_avatar.png'}/>
                        ) : (
                          <span>{usersMap[msg.sender]?.name.charAt(0).toUpperCase()}</span>
                        )
                      )}
                    </div>
                    <div className={styles.messageContentWrapper}>
                      <span className={styles.messageSender}>
                      {usersMap[msg.sender]?.name || msg.sender}
                      </span>
                      <div className={styles.messageContent}>
                        {msg.content && <p>{msg.content}</p>}
                        {msg.media && (
                          <img src={msg.media} alt="Shared media" className={styles.messageMedia} />
                        )}
                        <div className={styles.messageTime}>
                          {new Date(msg.timestamp).toLocaleTimeString()}
                        </div>
                        <div className={styles.reactions}>
                          {msg.reactions && Object.entries(msg.reactions).map(([emoji, count]) => (
                            <span key={emoji} className={styles.reaction}>
                              {emoji} {count}
                            </span>
                          ))}
                        </div>
                        <MessageReactions
                          messageId={msg.id}
                          conversationId={conversationId}
                          onAddReaction={(reaction) => handleAddReaction(msg.id, reaction)}
                        />
                      </div>
                    </div>
                  </div>
                ))}
                <div ref={messagesEndRef} />
              </div>
              <form onSubmit={handleSendMessage} className={styles.messageForm}>
                <input
                  type="text"
                  value={message}
                  onChange={(e) => setMessage(e.target.value)}
                  placeholder="Écrivez votre message..."
                  className={styles.messageInput}
                />
                <input
                  type="file"
                  accept="image/*"
                  onChange={handleFileChange}
                  id="file-upload"
                  style={{ display: 'none' }}
                />
                <label htmlFor="file-upload" className={styles.uploadButton}>
                  <IoImageOutline />
                </label>
                {selectedFile && (
                  <div className={styles.previewContainer}>
                    <img src={previewImage} alt="Preview" className={styles.previewImage} />
                    <button type="button" onClick={removeSelectedFile} className={styles.removePreviewButton}>
                      <IoCloseOutline />
                    </button>
                  </div>
                )}
                <button type="submit" className={styles.sendButton}>
                  <IoSend />
                </button>
              </form>
            </>
          )
        ) : (
          <div className={styles.welcomeMessage}>
            <h2>Bienvenue dans votre messagerie</h2>
            <p>Sélectionnez une conversation ou créez-en une nouvelle pour commencer à discuter.</p>
          </div>
        )}
      </main>

      {isCreateModalOpen && (
        <CreateConversationModal onClose={closeCreateModal} onConversationCreated={fetchConversations} />
      )}
    </div>
  );
}

export default Chat;

// frontend/src/components/Chat/CreateConversationModal.js
import React, { useState, useEffect, useContext } from 'react';
import { motion } from 'framer-motion';
import styles from './CreateConversationModal.module.css';
import axios from '../../utils/api';
import { AuthContext } from '../../contexts/AuthContext';

function CreateConversationModal({ onClose, onConversationCreated }) {
  const { user } = useContext(AuthContext);
  const [name, setName] = useState('');
  const [participants, setParticipants] = useState([]);
  const [allUsers, setAllUsers] = useState([]);
  const [searchUser, setSearchUser] = useState('');
  const [error, setError] = useState('');

  useEffect(() => {
    fetchAllUsers();
  }, []);

  const fetchAllUsers = async () => {
    try {
      const response = await axios.get('/users');
      // Exclude current user from participants
      const otherUsers = response.data.filter(u => u.name !== user.name);
      setAllUsers(otherUsers);
    } catch (error) {
      console.error('Error fetching users:', error);
      setError('Error loading users.');
    }
  };

  const handleToggleParticipant = (userName) => {
    if (participants.includes(userName)) {
      setParticipants(participants.filter(p => p !== userName));
    } else {
      setParticipants([...participants, userName]);
    }
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (participants.length === 0) {
      setError('Please add at least one participant.');
      return;
    }
    try {
      const conversationData = {
        name: name.trim() || null,
        participants,
      };
      await axios.post('/conversations', conversationData);
      onConversationCreated();
      onClose();
    } catch (error) {
      console.error('Error creating conversation:', error);
      setError('Failed to create conversation.');
    }
  };

  const filteredUsers = allUsers.filter(u =>
    u.name.toLowerCase().includes(searchUser.toLowerCase())
  );

  return (
    <div className={styles.overlay}>
      <motion.div
        className={styles.modal}
        initial={{ opacity: 0, scale: 0.9 }}
        animate={{ opacity: 1, scale: 1 }}
        exit={{ opacity: 0, scale: 0.9 }}
        transition={{ duration: 0.3 }}
      >
        <h2>Create a New Conversation</h2>
        <form onSubmit={handleSubmit}>
          <div className={styles.inputGroup}>
            <label>Conversation Name (Optional)</label>
            <input
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="Enter conversation name"
            />
          </div>

          <div className={styles.inputGroup}>
            <label>Add Participants</label>
            <input
              type="text"
              placeholder="Search users..."
              value={searchUser}
              onChange={(e) => setSearchUser(e.target.value)}
            />
            <div className={styles.usersList}>
              {filteredUsers.map(user => (
                <div key={user.id} className={styles.userItem}>
                  <label>
                    <input
                      type="checkbox"
                      checked={participants.includes(user.name)}
                      onChange={() => handleToggleParticipant(user.name)}
                    />
                    {user.name}
                  </label>
                </div>
              ))}
            </div>
          </div>

          <div className={styles.participants}>
            <h3>Selected Participants:</h3>
            {participants.map(name => (
              <div key={name} className={styles.participantItem}>
                <span>{name}</span>
                <button type="button" onClick={() => handleToggleParticipant(name)}>
                  Remove
                </button>
              </div>
            ))}
          </div>

          {error && <div className={styles.error}>{error}</div>}

          <div className={styles.buttonGroup}>
            <button type="button" onClick={onClose} className={styles.cancelButton}>
              Cancel
            </button>
            <button type="submit" className={styles.createButton}>
              Create
            </button>
          </div>
        </form>
      </motion.div>
    </div>
  );
}

export default CreateConversationModal;

// frontend/src/components/Chat/MessageReactions.js
import React from 'react';
import { IoHappy, IoThumbsUp, IoHeart } from 'react-icons/io5';
import styles from './MessageReactions.module.css';
import axios from '../../utils/api';

const availableReactions = [
  { emoji: '😊', label: 'Happy', icon: <IoHappy /> },
  { emoji: '👍', label: 'Thumbs Up', icon: <IoThumbsUp /> },
  { emoji: '❤️', label: 'Heart', icon: <IoHeart /> },
];

function MessageReactions({ messageId, conversationId, onAddReaction }) {
  const handleAddReaction = async (reaction) => {
    try {
      await axios.post(`/conversations/${conversationId}/messages/${messageId}/reactions`, { reaction });
      onAddReaction(reaction);
    } catch (error) {
      console.error('Erreur lors de l\'ajout de la réaction :', error);
    }
  };

  return (
    <div className={styles.reactionsContainer}>
      {availableReactions.map((reaction) => (
        <button
          key={reaction.emoji}
          className={styles.reactionButton}
          onClick={() => handleAddReaction(reaction.emoji)}
          aria-label={reaction.label}
        >
          {reaction.icon}
        </button>
      ))}
    </div>
  );
}

export default MessageReactions;

// frontend/src/components/Drive/AddFile.js
import React, { useState } from 'react';
import axios from '../../utils/api';
import { useNavigate } from 'react-router-dom';
import styles from './AddFile.module.css';

const AddFile = () => {
  const [file, setFile] = useState(null);
  const [parentFolderId, setParentFolderId] = useState(null); // Use parent folder ID
  const [fileName, setFileName] = useState(''); // Use file name instead of folder name
  const [error, setError] = useState('');
  const navigate = useNavigate();

  const handleFileChange = (e) => {
    setFile(e.target.files[0]);
    setFileName(e.target.files[0].name); // Set file name when file is selected
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!file) {
      setError('Please select a file.');
      return;
    }

    const formData = new FormData();
    formData.append('file', file);

    // Append parent folder ID if it exists
    if (parentFolderId) {
        formData.append('parent_folder_id', parentFolderId);
    }

    try {
      await axios.post('/files', formData, { // Use /files endpoint
        headers: { 'Content-Type': 'multipart/form-data' },
      });
      navigate('/drive'); // Navigate to Drive after successful upload
    } catch (err) {
      console.error("File upload error:", err); // Log the error for debugging
      if (err.response && err.response.data && err.response.data.detail) {
        setError(err.response.data.detail); // Display detailed error message
      } else {
        setError('Error uploading file.'); // Generic error message
      }
    }
  };

  return (
    <div className={styles.container}>
      <h2>Add New File</h2>
      <form onSubmit={handleSubmit} className={styles.form}>
        {/* Optional: Input for parent folder ID */}
        <div className={styles.inputGroup}>
          <label htmlFor="parentFolderId">Parent Folder ID (Optional)</label>
          <input
            type="text"
            id="parentFolderId"
            value={parentFolderId || ''} // Allow empty value
            onChange={(e) => setParentFolderId(e.target.value || null)} // Set to null if empty
            className={styles.input}
          />
        </div>
        <div className={styles.inputGroup}>
          <label htmlFor="file">Select File</label>
          <input
            type="file"
            id="file"
            onChange={handleFileChange}
            required
            className={styles.input}
          />
        </div>
         <div className={styles.inputGroup}>
          <label htmlFor="fileName">File Name</label>
          <input
            type="text"
            id="fileName"
            value={fileName}
            onChange={(e) => setFileName(e.target.value)}
            required
            className={styles.input}
          />
        </div>
        {error && <p className={styles.error}>{error}</p>}
        <button type="submit" className={styles.submitButton}>
          Upload File
        </button>
      </form>
    </div>
  );
};

export default AddFile;

// frontend/src/components/Drive/Drive.js
import React, { useState, useEffect, useRef, useContext } from 'react';
import axios from '../../utils/api';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faFolder, faFile, faPlus, faTrash, faEdit, faShareAlt, faArrowLeft, faCheck, faTimes } from '@fortawesome/free-solid-svg-icons';
import styles from './Drive.module.css';
import { confirmAlert } from 'sweetalert2';
import { AuthContext } from '../../contexts/AuthContext';

const Drive = () => {
    const [files, setFiles] = useState([]);
    const [folders, setFolders] = useState([]);
    const [error, setError] = useState('');
    const [newFolderName, setNewFolderName] = useState('');
    const [currentFolderId, setCurrentFolderId] = useState(null);
    const [pathStack, setPathStack] = useState([]);
    const [currentPath, setCurrentPath] = useState('Root');
    const [loading, setLoading] = useState(false);

    const { user } = useContext(AuthContext);

    useEffect(() => {
        fetchFoldersAndFiles();
    }, [currentFolderId]);

    const fetchFoldersAndFiles = async () => {
        setLoading(true);
        try {
            const response = await axios.get(`/folders/${currentFolderId || 'null'}/contents`);
            setFolders(response.data.folders);
            setFiles(response.data.files);
        } catch (err) {
            setError('Error fetching data.');
        } finally {
            setLoading(false);
        }
    };

    const createFolder = async () => {
        if (!newFolderName.trim()) {
            setError('Folder name cannot be empty.');
            return;
        }
        try {
            const response = await axios.post('/folders', {
                folder_name: newFolderName,
                parent_folder_id: currentFolderId || null,  // Send null for root
            });
            setNewFolderName('');
            fetchFoldersAndFiles();
        } catch (err) {
            console.error("Error creating folder:", err); // Add error logging
            setError(err?.response?.data?.detail || 'Error creating folder.'); // More specific error message
        }
    };

    const navigateToFolder = (folder) => {
        setPathStack([...pathStack, { id: currentFolderId, name: currentPath }]);
        setCurrentFolderId(folder.id);
        setCurrentPath(folder.name);
    };

    const navigateBack = () => {
        const newPathStack = [...pathStack];
        const previous = newPathStack.pop() || { id: null, name: 'Root' };
        setPathStack(newPathStack);
        setCurrentFolderId(previous.id);
        setCurrentPath(previous.name);
    };

    const handleFileUpload = async (e) => {
        const file = e.target.files[0];
        if (file) {
            try {
                const formData = new FormData();
                formData.append('file', file);
                formData.append('parent_folder_id', currentFolderId || null); // Send null for root

                await axios.post('/files', formData, {
                    headers: { 'Content-Type': 'multipart/form-data' },
                });
                fetchFoldersAndFiles();
            } catch (error) {
                console.error("Error uploading file:", error);
                setError(error?.response?.data?.detail || 'Error uploading file.');
            }
        }
    };

    const deleteFile = async (fileId) => {
        confirmAlert({
            title: "Confirmation",
            text: "Are you sure you want to delete this file?",
            icon: 'warning',
            showCancelButton: true,
            confirmButtonText: "Yes, delete it!",
            cancelButtonText: "No, cancel",
            onConfirm: async () => {
                try {
                    await axios.delete(`/files/${fileId}`);
                    fetchFoldersAndFiles();
                } catch (err) {
                    setError('Error deleting file.');
                }
            }
        });
    };

    const deleteFolder = async (folderId) => {
        confirmAlert({
            title: 'Confirmation',
            text: 'Are you sure you want to delete this folder? This action is irreversible and will delete all subfolders and files within it.',
            icon: 'warning',
            showCancelButton: true,
            confirmButtonText: 'Yes, delete it!',
            cancelButtonText: 'No, cancel',

            onConfirm: async () => {
                try {
                    await axios.delete(`/folders/${folderId}`);
                    fetchFoldersAndFiles();
                } catch (err) {
                  console.error("Error deleting folder:", err);
                  setError(err?.response?.data?.detail || 'Error deleting folder.');
                }
            }
        });
    };

    const handleRename = async (item, isFile) => {
        const newName = prompt('Enter new name', item.name);
        if (newName && newName !== item.name) {
            confirmAlert({
                title: "Confirmation",
                text: `Are you sure you want to rename "${item.name}" to "${newName}"?`,
                icon: 'question',
                showCancelButton: true,
                confirmButtonText: "Yes, rename it!",
                cancelButtonText: "No, cancel",
                onConfirm: async () => {

                    try {
                        if (isFile) {
                            await axios.put(`/files/${item.id}/rename`, { new_name: newName });
                        } else {
                            await axios.put(`/folders/${item.id}/rename`, { new_name: newName });
                        }
                        fetchFoldersAndFiles();
                    } catch (err) {
                        setError('Error renaming item.');
                    }
                }
            })
        }
    };

    const handleShare = async (item, isFile) => {
        const sharedUserName = prompt('Enter username to share with');
        if (sharedUserName) {
            try {
                if (isFile) {
                    await axios.post(`/files/${item.id}/share`, { shared_user_name: sharedUserName });
                } else {
                    await axios.post(`/folders/${item.id}/share`, { shared_user_name: sharedUserName });
                }
                alert('Item shared successfully.'); // Consider a less intrusive notification
            } catch (err) {
                console.error("Error sharing item:", err);
                setError(err?.response?.data?.detail || 'Error sharing item.');
            }
        }
    };

    return (
        <div className={styles.container}>
            <h2>Your Drive</h2>
            {error && <p className={styles.error}>{error}</p>}
            {loading && <div className={styles.loader}>Loading...</div>}
            <div className={styles.navigation}>
                <button onClick={navigateBack} disabled={!pathStack.length} className={styles.backButton}>
                    <FontAwesomeIcon icon={faArrowLeft} /> Back
                </button>
                <span>{currentPath}</span>
            </div>
            <div className={styles.folderActions}>
                <input
                    type="text"
                    placeholder="New Folder"
                    value={newFolderName}
                    onChange={e => setNewFolderName(e.target.value)}
                    onKeyPress={e => e.key === 'Enter' && createFolder()}
                />
                <button onClick={createFolder}>
                    <FontAwesomeIcon icon={faPlus} /> New Folder
                </button>
                <label className={styles.uploadLabel}>
                    <FontAwesomeIcon icon={faPlus} /> Upload File
                    <input type="file" onChange={handleFileUpload} className={styles.fileInput} />
                </label>
            </div>
            <div className={styles.itemsContainer}>
                <h3>Folders</h3>
                <ul className={styles.itemsList}>
                    {folders.map((folder) => (
                        <li key={folder.id} className={styles.item}>
                            <FontAwesomeIcon icon={faFolder} className={styles.itemIcon} />
                            <span className={styles.itemName} onClick={() => navigateToFolder(folder)}>
                                {folder.name}
                            </span>
                            <div className={styles.itemActions}>
                                <button onClick={() => handleRename(folder, false)} title="Rename">
                                    <FontAwesomeIcon icon={faEdit} />
                                </button>
                                <button onClick={() => handleShare(folder, false)} title="Share">
                                    <FontAwesomeIcon icon={faShareAlt} />
                                </button>
                                <button onClick={() => deleteFolder(folder.id)} title="Delete">
                                    <FontAwesomeIcon icon={faTrash} />
                                </button>
                            </div>
                        </li>
                    ))}
                </ul>
                <h3>Files</h3>
                <ul className={styles.itemsList}>
                    {files.map((file) => (
                        <li key={file.id} className={styles.item}>
                            <FontAwesomeIcon icon={faFile} className={styles.itemIcon} />
                            <a href={file.url} target="_blank" rel="noopener noreferrer" className={styles.itemName}>
                                {file.name}
                            </a>
                            <div className={styles.itemActions}>
                                <button onClick={() => handleRename(file, true)} title="Rename">
                                    <FontAwesomeIcon icon={faEdit} />
                                </button>
                                <button onClick={() => handleShare(file, true)} title="Share">
                                    <FontAwesomeIcon icon={faShareAlt} />
                                </button>
                                <button onClick={() => deleteFile(file.id)} title="Delete">
                                    <FontAwesomeIcon icon={faTrash} />
                                </button>
                            </div>
                        </li>
                    ))}
                </ul>
            </div>
        </div>
    );
};

export default Drive;

// frontend/src/components/FileUpload/FileUpload.js
import React, { useState, useCallback, useRef } from 'react';
import { useDropzone } from 'react-dropzone';
import axios from '../../utils/api';
import styles from './FileUpload.module.css';

const FileUpload = ({ onUpload, maxSize = 50 * 1024 * 1024, parentFolderId = null }) => {
    const [uploadProgress, setUploadProgress] = useState(0);
    const [error, setError] = useState(null);
    const [isUploading, setIsUploading] = useState(false);
    const cancelTokenRef = useRef(null);

    const onDrop = useCallback(async (acceptedFiles) => {
        const file = acceptedFiles[0];
        if (!file) return;

        setError(null);
        setIsUploading(true);
        setUploadProgress(0);

        const formData = new FormData();
        formData.append('file', file);
        if (parentFolderId) {
            formData.append('parent_folder_id', parentFolderId);
        }

        // Create cancel token
        cancelTokenRef.current = axios.CancelToken.source();

        try {
            const response = await axios.post('/files', formData, {
                headers: { 'Content-Type': 'multipart/form-data' },
                onUploadProgress: (progressEvent) => {
                    const progress = (progressEvent.loaded / progressEvent.total) * 100;
                    setUploadProgress(Math.round(progress));
                },
                cancelToken: cancelTokenRef.current.token
            });

            onUpload(response.data);
            setError(null);
        } catch (err) {
            if (axios.isCancel(err)) {
                setError('Upload cancelled');
            } else {
                setError(err.response?.data?.detail || 'Upload failed');
            }
        } finally {
            setIsUploading(false);
            setUploadProgress(0);
        }
    }, [onUpload, parentFolderId]);

    const cancelUpload = () => {
        if (cancelTokenRef.current) {
            cancelTokenRef.current.cancel('Upload cancelled by user');
        }
    };

    const { getRootProps, getInputProps, isDragActive } = useDropzone({
        onDrop,
        maxSize,
        accept: {
            'image/*': ['.jpg', '.jpeg', '.png'],
            'application/pdf': ['.pdf'],
            'application/msword': ['.doc', '.docx'],
            'text/plain': ['.txt']
        },
        multiple: false
    });

    return (
        <div className={styles.uploadContainer}>
            <div
                {...getRootProps()}
                className={`${styles.dropzone} ${isDragActive ? styles.active : ''}`}
            >
                <input {...getInputProps()} />
                {isDragActive ? (
                    <p>Drop the file here...</p>
                ) : (
                    <div className={styles.uploadPrompt}>
                        <p>Drag & drop a file here, or click to select</p>
                        <p className={styles.supportedFormats}>
                            Supported formats: JPG, PNG, PDF, DOC, DOCX, TXT
                        </p>
                        <p className={styles.maxSize}>
                            Maximum file size: {Math.round(maxSize / (1024 * 1024))}MB
                        </p>
                    </div>
                )}
            </div>

            {isUploading && (
                <div className={styles.uploadProgress}>
                    <div className={styles.progressBar}>
                        <div
                            className={styles.progressFill}
                            style={{ width: `${uploadProgress}%` }}
                        />
                    </div>
                    <p>{uploadProgress}% uploaded</p>
                    <button
                        onClick={cancelUpload}
                        className={styles.cancelButton}
                    >
                        Cancel Upload
                    </button>
                </div>
            )}

            {error && (
                <div className={styles.error}>
                    <p>{error}</p>
                </div>
            )}
        </div>
    );
};

export default FileUpload;

// frontend/src/components/Profile/Profile.js
import React, { useState, useEffect, useContext } from 'react';
import axios from '../../utils/api';
import styles from './Profile.module.css';
import { AuthContext } from '../../contexts/AuthContext';
import { useNavigate } from 'react-router-dom';

const Profile = () => {
  const { user, setUser } = useContext(AuthContext);
  const [bio, setBio] = useState('');
  const [editingBio, setEditingBio] = useState(false);
  const [selectedFile, setSelectedFile] = useState(null);
  const [previewImage, setPreviewImage] = useState(null);
  const [error, setError] = useState('');
  const navigate = useNavigate();

  useEffect(() => {
    setBio(user.bio || '');
  }, [user.bio]);


  const handleInputChange = (e) => {
    setBio(e.target.value);
  };

  const handleSaveBio = async () => {
    try {
      const response = await axios.put('/users/me/bio', { bio });
      setEditingBio(false);
      setUser(prevUser => ({
        ...prevUser,
        bio: response.data.bio,
      }));
      localStorage.setItem('user', JSON.stringify(response.data));
    } catch (err) {
      setError('Erreur lors de la sauvegarde de la bio.');
    }
  };

  const handleFileChange = (e) => {
    const file = e.target.files[0];
    setSelectedFile(file);
    setPreviewImage(URL.createObjectURL(file));
  };

  const handleAvatarUpload = async () => {
    const file = selectedFile;
    if (!file) return;

    const formData = new FormData();
    formData.append('file', file);

    try {
      const response = await axios.post('/upload/avatar', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      });

      const { avatar_url } = response.data;
      setUser(prevUser => ({
        ...prevUser,
        avatar_url,
      }));

      localStorage.setItem('user', JSON.stringify({ ...user, avatar_url }));

      setSelectedFile(null);
      setPreviewImage(null);
      setError('');
    } catch (error) {
      setError('Erreur lors du téléchargement de l\'avatar.');
    }
  };

  const removeSelectedFile = () => {
    setSelectedFile(null);
    setPreviewImage(null);
  };

  return (
    <div className={styles.container}>
      <div className={styles.glassOverlay}>
        <div className={styles.profileHeader}>
          <div className={styles.avatarContainer}>
            <div className={styles.avatar}>
              {user.avatar_url ? (
                <img src={user.avatar_url} alt="Avatar" className={styles.avatarImage} onError={(e) => e.target.src='default_avatar.png'}/>
              ) : (
                <span>{user.name.charAt(0).toUpperCase()}</span>
              )}
            </div>
            <input
              type="file"
              accept="image/*"
              onChange={handleFileChange}
              id="avatar-upload"
              style={{ display: 'none' }}
            />
            <label htmlFor="avatar-upload" className={styles.uploadLabel}>
              Change Avatar
            </label>
            {selectedFile && (
              <button onClick={handleAvatarUpload} className={styles.uploadButton}>
                Upload
              </button>
            )}
          </div>
          <h1 className={styles.username}>{user.name}</h1>
        </div>

        <div className={styles.bioSection}>
          {editingBio ? (
            <div className={styles.editContainer}>
              <textarea
                value={bio || ''}
                onChange={handleInputChange}
                className={styles.bioInput}
                placeholder="Écrivez quelque chose à propos de vous..."
              />
              <div className={styles.buttonGroup}>
                <button onClick={() => setEditingBio(false)} className={styles.cancelButton}>
                  Annuler
                </button>
                <button onClick={handleSaveBio} className={styles.saveButton}>
                  Enregistrer
                </button>
              </div>
            </div>
          ) : (
            <div className={styles.bioContainer}>
              <p className={styles.bioText}>{bio || "Aucune bio définie."}</p>
              <button onClick={() => setEditingBio(true)} className={styles.editButton}>
                Modifier le profil
              </button>
            </div>
          )}
          {error && <div className={styles.error}>{error}</div>}
          {selectedFile && (
            <div>
              <img src={previewImage} alt="Preview" className={styles.imagePreview} />
              <button onClick={removeSelectedFile} className={styles.closeButton}>
                Supprimer
              </button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

export default Profile;

// services/fileService.js
import api from '../utils/api';

export const fileService = {
    async uploadFile(file, folderId = null, onProgress) {
        const formData = new FormData();
        formData.append('file', file);
        if (folderId) {
            formData.append('parent_folder_id', folderId);
        }

        try {
            const response = await api.post('/files', formData, {
                headers: { 'Content-Type': 'multipart/form-data' },
                onUploadProgress: (progressEvent) => {
                    if (onProgress) {
                        const progress = (progressEvent.loaded / progressEvent.total) * 100;
                        onProgress(Math.round(progress));
                    }
                }
            });
            return response.data;
        } catch (error) {
            throw new Error(error.response?.data?.detail || 'Upload failed');
        }
    },

    async deleteFile(fileId) {
        try {
            await api.delete(`/files/${fileId}`);
        } catch (error) {
            throw new Error(error.response?.data?.detail || 'Delete failed');
        }
    }
};
// frontend/src/components/Design.js
import React from 'react';
import { createGlobalStyle } from 'styled-components';

const Design = ({ children }) => {
  return (
    <>
      {createGlobalStyle(`
        body {
          background-color: #f5f5f5;
          color: #000;
          font-family: 'Helvetica Neue', sans-serif;
          margin: 0;
          padding: 0;
        }
      `)}
      {children}
    </>
  );
};

export default Design;

// frontend/src/components/Home.js
import React, { useState, useEffect, useRef, useContext } from 'react';
import { AuthContext } from '../contexts/AuthContext';
import { useNavigate } from 'react-router-dom';
import styles from './Home.module.css';
import backgroundVideo from './Space.mp4';

function Home() {
  const { user } = useContext(AuthContext);
  const navigate = useNavigate();
  const [scrollProgress, setScrollProgress] = useState(0);
  const sectionsRef = useRef([]);

  const handleLogin = () => navigate('/login');
  const handleSignUp = () => navigate('/signup');
  const handleStartChat = () => navigate('/conversations');

  useEffect(() => {
    const handleScroll = () => {
      // Calculate scroll progress (0 to 1)
      const totalHeight = document.documentElement.scrollHeight - window.innerHeight;
      const progress = window.scrollY / totalHeight;
      setScrollProgress(progress);

      // Check each section for visibility
      sectionsRef.current.forEach(section => {
        if (!section) return;
        const rect = section.getBoundingClientRect();
        const isVisible = rect.top < window.innerHeight * 0.75;
        if (isVisible) {
          section.classList.add(styles.revealed);
        }
      });
    };

    window.addEventListener('scroll', handleScroll);
    handleScroll(); // Initial check

    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  // Progress line width calculation
  const progressWidth = `${scrollProgress * 100}%`;

  return (
    <div className={styles.mainContainer}>
      {/* Progress Line */}
      <div className={styles.progressLine}>
        <div className={styles.progressFill} style={{ width: progressWidth }} />
      </div>

      {/* Background Video */}
      <div className={styles.videoOverlay} style={{
        opacity: Math.min(0.4 + scrollProgress * 0.4, 0.8)
      }} />
      <video
        autoPlay
        muted
        loop
        playsInline
        className={styles.backgroundVideo}
      >
        <source src={backgroundVideo} type="video/mp4" />
      </video>

      {/* Hero Section */}
      <section
        className={`${styles.section} ${styles.heroSection}`}
        ref={el => sectionsRef.current[0] = el}
      >
        <div className={styles.contentWrapper}>
          {user.name ? (
            <div className={styles.authenticatedContent}>
              <div className={styles.avatarWrapper}>
                <div className={styles.avatar}>
                  {user.name.charAt(0).toUpperCase()}
                </div>
              </div>
              <h1 className={styles.welcomeText}>
                Welcome back, <span className={styles.userName}>{user.name}</span>
              </h1>
              <button className={styles.mainButton} onClick={handleStartChat}>
                Go to Conversations
              </button>
            </div>
          ) : (
            <div className={styles.unauthenticatedContent}>
              <h1 className={styles.heroTitle}>Connect to Start Chatting</h1>
              <p className={styles.heroText}>
                Join a dynamic community and communicate in real-time
              </p>
              <div className={styles.actionButtons}>
                <button className={styles.mainButton} onClick={handleLogin}>
                  Login
                </button>
                <button className={styles.mainButton} onClick={handleSignUp}>
                  Signup
                </button>
              </div>
            </div>
          )}
        </div>
      </section>

      {/* Features Section */}
      <section
        className={`${styles.section} ${styles.featuresSection}`}
        ref={el => sectionsRef.current[1] = el}
      >
        <div className={styles.contentWrapper}>
          <h2 className={styles.sectionTitle}>Our Features</h2>
          <div className={styles.featuresGrid}>
            {[
              { icon: '🔒', title: 'Secure', desc: 'End-to-end encryption' },
              { icon: '⚡', title: 'Fast', desc: 'Real-time communication' },
              { icon: '🌐', title: 'Global', desc: 'Accessible everywhere' },
              { icon: '📱', title: 'Responsive', desc: 'Mobile-friendly interface' },
              { icon: '🎨', title: 'Customizable', desc: 'Themes and avatars' },
              { icon: '📂', title: 'Media Sharing', desc: 'Share images, videos, and documents' },
            ].map((feature, index) => (
              <div
                key={index}
                className={styles.featureCard}
                style={{ transitionDelay: `${index * 0.1}s` }}
              >
                <span className={styles.featureIcon}>{feature.icon}</span>
                <h3>{feature.title}</h3>
                <p>{feature.desc}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Stats Section */}
      <section
        className={`${styles.section} ${styles.statsSection}`}
        ref={el => sectionsRef.current[2] = el}
      >
        <div className={styles.contentWrapper}>
          <h2 className={styles.sectionTitle}>Our Stats</h2>
          <div className={styles.statsGrid}>
            {[
              { number: '10k+', label: 'Active Users' },
              { number: '500k+', label: 'Messages Sent' },
              { number: '99.9%', label: 'Uptime' },
            ].map((stat, index) => (
              <div
                key={index}
                className={styles.statCard}
                style={{ transitionDelay: `${index * 0.1}s` }}
              >
                <span className={styles.statNumber}>{stat.number}</span>
                <span className={styles.statLabel}>{stat.label}</span>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Contact Section */}
      <section
        className={`${styles.section} ${styles.contactSection}`}
        ref={el => sectionsRef.current[3] = el}
      >
        <div className={styles.contentWrapper}>
          <h2 className={styles.sectionTitle}>Get in Touch</h2>
          <div className={styles.contactContent}>
            <p className={styles.contactText}>
              Ready to join us?
            </p>
            <button className={styles.mainButton}>
              Start Chatting
            </button>
          </div>
        </div>
      </section>
    </div>
  );
}

export default Home;

// frontend/src/components/Navbar.js
import React, { useContext } from 'react';
import { Link } from 'react-router-dom';
import { AuthContext } from '../contexts/AuthContext';
import styles from './Navbar.module.css';

const Navbar = () => {
  const { user, setUser } = useContext(AuthContext);

  const handleLogout = () => {
    setUser(null);
    localStorage.removeItem('user');
    localStorage.removeItem('token');
  };

  return (
    <nav className={styles.navbar}>
      <ul className={styles.navList}>
        {user.name ? (
          <>
            <li className={styles.navItem}>
              <Link to="/conversations" className={styles.navLink}>Conversations</Link>
            </li>
            <li className={styles.navItem}>
              <Link to="/profile" className={styles.navLink}>Profil</Link>
            </li>
            <li className={styles.navItem}>
              <Link to="/settings" className={styles.navLink}>Paramètres</Link>
            </li>
            <li className={styles.navItem}>
              <Link to="/drive" className={styles.navLink}>Drive</Link>
            </li>
            <li className={styles.navItem}>
              <Link to="/addfile" className={styles.navLink}>Ajouter un fichier</Link>
            </li>
            <li className={styles.navItem}>
              <button onClick={handleLogout} className={styles.logoutButton}>Déconnexion</button>
            </li>
          </>
        ) : (
          <>
            <li className={styles.navItem}>
              <Link to="/login" className={styles.navLink}>Connexion</Link>
            </li>
            <li className={styles.navItem}>
              <Link to="/signup" className={styles.navLink}>Inscription</Link>
            </li>
          </>
        )}
      </ul>
    </nav>
  );
};

export default Navbar;

// frontend/src/components/Settings.js
import React, { useState, useEffect, useCallback } from 'react';
import styles from './Settings.module.css';

const Settings = () => {
  const [darkMode, setDarkMode] = useState(false);
  const [fontSize, setFontSize] = useState(16);
  const [theme, setTheme] = useState(localStorage.getItem('theme') || 'light');

  useEffect(() => {
    const storedTheme = localStorage.getItem('theme');
    if (storedTheme) {
      setTheme(storedTheme);
    }
  }, [theme]);

  const handleDarkModeToggle = useCallback(() => {
    const prevDarkMode = darkMode;
    setDarkMode(!prevDarkMode);
    document.documentElement.setAttribute('data-theme', prevDarkMode ? 'light' : 'dark');
  }, [darkMode]);

  const handleFontSizeChange = (event) => {
    setFontSize(event.target.value);
  };

  const handleThemeChange = (newTheme) => {
    setTheme(newTheme);
    localStorage.setItem('theme', newTheme);
    document.documentElement.setAttribute('data-theme', newTheme);
  };

  return (
    <div className={styles.container}>
      <h1 className={styles.title}>Paramètres</h1>
      <div className={styles.settingsContainer}>
        <div className={styles.settingItem}>
          <label htmlFor="darkModeToggle">Mode sombre</label>
          <input
            type="checkbox"
            checked={darkMode}
            onChange={handleDarkModeToggle}
            className={styles.toggle}
          />
        </div>
        <div className={styles.settingItem}>
          <label htmlFor="fontSizeSlider">Taille de la police</label>
          <input
            type="range"
            min="10"
            max="30"
            value={fontSize}
            onChange={handleFontSizeChange}
            className={styles.slider}
          />
        </div>
        <div className={styles.settingItem}>
          <label htmlFor="themeSelector">Thème</label>
          <select value={theme} onChange={(e) => handleThemeChange(e.target.value)} className={styles.select}>
            <option value="light" className={styles.option}>Mode clair</option>
            <option value="dark" className={styles.option}>Mode sombre</option>
          </select>
        </div>
      </div>
    </div>
  );
};

export default Settings;

// frontend/src/components/ThemeToggle.js
import React, { useEffect, useState } from 'react';
import { IoSunny, IoMoon } from 'react-icons/io5';
import styles from './ThemeToggle.module.css';

function ThemeToggle() {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    // Check for saved user preference
    const storedTheme = localStorage.getItem('app-theme') || 'light';
    setTheme(storedTheme);
    document.documentElement.setAttribute('data-theme', storedTheme);
  }, []);

  const toggleTheme = () => {
    const newTheme = theme === 'light' ? 'dark' : 'light';
    setTheme(newTheme);
    document.documentElement.setAttribute('data-theme', newTheme);
    localStorage.setItem('app-theme', newTheme);
  };

  return (
    <button className={styles.toggleButton} onClick={toggleTheme} aria-label="Toggle Theme">
      {theme === 'light' ? <IoMoon /> : <IoSunny />}
    </button>
  );
}

export default ThemeToggle;

// frontend/src/components/upload.js
const express = require('express');
const multer = require('multer');
const { v4: uuidv4 } = require('uuid');
const router = express.Router();
const path = require('path');

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    cb(null, uuidv4() + path.extname(file.originalname));
  }
});

const upload = multer({ storage: storage });

router.post('/avatar', upload.single('file'), (req, res) => {
  if (!req.file) {
    return res.status(400).send('No file uploaded.');
  }

  const avatar_url = `http://localhost:5000/uploads/${req.file.filename}`;
  res.json({ avatar_url });
});

module.exports = router;

// frontend/src/components/UserProfile.js
import React, { useEffect, useState, useContext } from 'react';
import { useParams } from 'react-router-dom';
import axios from '../utils/api';
import styles from './UserProfile.module.css';
import { AuthContext } from '../contexts/AuthContext';

function UserProfile() {
  const { username } = useParams();
  const [userData, setUserData] = useState(null);
  const { user: currentUser } = useContext(AuthContext);

  useEffect(() => {
    const fetchUserData = async () => {
      try {
        const response = await axios.get(`/users/${username}`);
        setUserData(response.data);
      } catch (error) {
        console.error('Erreur lors de la récupération du profil utilisateur', error);
      }
    };

    fetchUserData();
  }, [username]);

  if (!userData) {
    return <div>Chargement du profil...</div>;
  }

  return (
    <div className={styles.profileContainer}>
      <div className={styles.avatar}>
        {userData.avatar_url ? (
          <img src={userData.avatar_url} alt={`${userData.name} Avatar`} onError={(e) => e.target.src='default_avatar.png'}/>
        ) : (
          <span>{userData.name.charAt(0).toUpperCase()}</span>
        )}
      </div>
      <h2>{userData.name}</h2>
      <p>{userData.bio}</p>
      {currentUser.name === userData.name && (
        <p>Ceci est votre profil</p>
      )}
    </div>
  );
}

export default UserProfile;

// frontend/src/contexts/AuthContext.js
import React, { createContext, useState, useEffect } from 'react';
import axios from '../utils/api';

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState({
    id: '',
    name: '',
    bio: '',
    avatar_url: ''
  });

  useEffect(() => {
    const storedUser = localStorage.getItem('user');
    const storedToken = localStorage.getItem('token');
    if (storedUser && storedToken) {
      const parsedUser = JSON.parse(storedUser);
      setUser({
        id: parsedUser.id || '',
        name: parsedUser.name || '',
        bio: parsedUser.bio || '',
        avatar_url: parsedUser.avatar_url || ''
      });
      axios.defaults.headers.common['Authorization'] = `Bearer ${storedToken}`;
    }
  }, []);

  const login = async (username, password) => {
    const response = await axios.post('/login', {
      name: username,
      password: password,
    });
    const { access_token } = response.data;
    localStorage.setItem('token', access_token);
    axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`;

    const userResponse = await axios.get('/users/me');
    const fetchedUser = userResponse.data;
    localStorage.setItem('user', JSON.stringify(fetchedUser));
    setUser({
      id: fetchedUser.id || '',
      name: fetchedUser.name || '',
      bio: fetchedUser.bio || '',
      avatar_url: fetchedUser.avatar_url || ''
    });
  };

  const signup = async (username, password) => {
    await axios.post('/signup', {
      name: username,
      password: password,
    });
    await login(username, password);
  };

  const logout = () => {
    localStorage.removeItem('user');
    localStorage.removeItem('token');
    delete axios.defaults.headers.common['Authorization'];
    setUser({
      id: '',
      name: '',
      bio: '',
      avatar_url: ''
    });
  };

  return (
    <AuthContext.Provider value={{ user, login, signup, logout, setUser }}>
      {children}
    </AuthContext.Provider>
  );
};

// src/utils/api.js
import axios from 'axios';

const api = axios.create({
  baseURL: process.env.REACT_APP_API_URL , // Remplacez par votre URL de backend
});

export const fileService = {
    async uploadFile(file, folderId = null) {
        try {
            const formData = new FormData();
            formData.append('file', file);
            if (folderId) {
                formData.append('parent_folder_id', folderId);
            }

            const response = await api.post('/files', formData, {
                headers: { 'Content-Type': 'multipart/form-data' },
                onUploadProgress: (progressEvent) => {
                    const percentCompleted = Math.round(
                        (progressEvent.loaded * 100) / progressEvent.total
                    );
                }
            });
            return response.data;
        } catch (error) {
            throw new Error(error.response?.data?.detail || 'Upload failed');
        }
    }
};

export default api;

// frontend/src/App.js
import React, { useContext } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { AuthContext } from './contexts/AuthContext';
import Login from './components/Auth/Login';
import Signup from './components/Auth/Signup';
import Home from './components/Home';
import Chat from './components/Chat/Chat';
import Profile from './components/Profile/Profile';
import Navbar from './components/Navbar';
import UserProfile from './components/UserProfile';
import Settings from './components/Settings';
import Drive from './components/Drive/Drive'; // Import the Drive component
import AddFile from './components/Drive/AddFile'; // Import the AddFile component

function App() {
  const { user } = useContext(AuthContext);

  return (
    <Router>
      <Navbar />
      <Routes>
        <Route path="/" element={user.name ? <Navigate to="/conversations" /> : <Home />} />
        <Route path="/login" element={user.name ? <Navigate to="/conversations" /> : <Login />} />
        <Route path="/signup" element={user.name ? <Navigate to="/conversations" /> : <Signup />} />
        <Route path="/profile" element={user.name ? <Profile /> : <Navigate to="/login" />} />
        <Route path="/conversations" element={user.name ? <Chat /> : <Navigate to="/login" />} />
        <Route path="/chat/:conversationId" element={user.name ? <Chat /> : <Navigate to="/login" />} />
        <Route path="/users/:username" element={user.name ? <UserProfile /> : <Navigate to="/login" />} />
        <Route path="/settings" element={user.name ? <Settings /> : <Navigate to="/login" />} />
        <Route path="/drive" element={user.name ? <Drive /> : <Navigate to="/login" />} /> {/* Add the Drive route */}
        <Route path="/addfile" element={user.name ? <AddFile /> : <Navigate to="/login" />} /> {/* Add the AddFile route */}
        <Route path="*" element={<Navigate to="/" replace />} />
      </Routes>
    </Router>
  );
}

export default App;

// frontend/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { AuthProvider } from './contexts/AuthContext';
import './index.css';

ReactDOM.render(
  <AuthProvider>
    <App />
  </AuthProvider>,
  document.getElementById('root')
);