import os
import shutil
from fastapi import APIRouter, Depends, Request, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.responses import JSONResponse
from sqlalchemy.orm import Session, joinedload
from dotenv import load_dotenv
import db_config.database as dbase
from db_config.models import User, Folder, Documents
import db_config.schemas as schemas
import db_config.auth as auth
from dependencies.helper import *
from dependencies.awsutils import S3Service
router = APIRouter()
security = HTTPBearer()
load_dotenv()

DB_FOLDER = str(os.getenv('DB_PATH'))+"/"
UPLOAD_FOLDER = str(os.getenv('STORAGE_PATH'))+"/"

# Get all folders
@router.get("/list", response_model=schemas.FolderListResponse)
async def get_folders(credentials: HTTPAuthorizationCredentials = Depends(security)):
    db = dbase.SessionLocal()
    token = credentials.credentials
    user = auth.get_current_user(db, token)
    try:
        folders = db.query(Folder).filter(Folder.user_id == user.user_id).options(joinedload(Folder.documents)).all()
        
        if not folders:
            return errorResponse(
                "Folder does not exist."
            )
        
        folder_data = [schemas.FolderResponse.from_orm(folder) for folder in folders]
    

        return successReponse(
            "Folders retrieved successfully",
            [folder.dict() for folder in folder_data]
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")
    

# Create a folders
@router.post("/create")
async def create_folder(
    folder: schemas.FolderCreate,
    credentials: HTTPAuthorizationCredentials = Depends(security), 
    db: Session = Depends(dbase.get_db)
):
    token = credentials.credentials
    user = auth.get_current_user(db, token)
    try:
        folder_name = folder.folder_name.strip() if folder.folder_name else ''
        folder_name = normalize_spaces(folder_name)
        shared_type = folder.shared if folder.shared else 'No'
        if not folder_name: 
            return errorResponse(
                "Folder name is required."
            )
        if folder_name:
            if any(char in folder_name for char in "\[]}{\\$&%#@)()+!^."):
                return errorResponse("Folder name contains characters only.")

        if shared_type != 'Yes' and shared_type != 'No':
            shared_type = 'No'
            # return errorResponse(
            #     'Share must be only "Yes" or "No".'
            # )
        folder_name = folder_name[:20].strip() if len(folder_name) > 20 else folder_name
        
        existing_folder = db.query(Folder).filter(Folder.name == folder_name).filter(Folder.user_id == user.user_id).first()
        if existing_folder: 
            return errorResponse(
                "This folder already exists. Please give a unique name."
            )
        sanitized_name = replace_special_characters(folder_name)
        s3_service = S3Service()
        new_folder = Folder(
            name=folder_name, 
            parent_id=folder.parent_id if folder.parent_id else '0',
            user_id = user.user_id,
            shared = shared_type,
            sanitized_name = sanitized_name
        )
        db.add(new_folder)
        db.commit()
        db.refresh(new_folder)
        
        chroma_dir_name = str(DB_FOLDER)+str(user.user_code)+'/'+str(new_folder.sanitized_name)
        storage_dir_name = str(UPLOAD_FOLDER)+str(user.user_code)+'/'+str(new_folder.sanitized_name)
        if not os.path.exists(chroma_dir_name):
            os.makedirs(chroma_dir_name)

        if not os.path.exists(storage_dir_name):
            os.makedirs(storage_dir_name)
        
        s3_service.create_directory(storage_dir_name)

        # return new_folder
        return successReponse(
            "Folder successfully created.",
            schemas.FolderResponse.from_orm(new_folder).dict()
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")

# Update a folders
'''
Update Folder 
'''
@router.put("/update/{folder_id}")
async def update_folder(folder_id: int, folder: schemas.FolderCreate, credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(dbase.get_db)):
    token = credentials.credentials
    user = auth.get_current_user(db, token)
    try:
        existing_folder = db.query(Folder).filter(Folder.folder_id == folder_id).filter(Folder.user_id == user.user_id).first()
        if not existing_folder:
            return errorResponse(
                "Folder not found"
            )
        
        folder_name = folder.folder_name.strip() if folder.folder_name else ''
        folder_name = normalize_spaces(folder_name)
        shared_type = folder.shared if folder.shared else 'No'
        if not folder_name: 
            return errorResponse(
                "Folder name is required."
            )
        if folder_name:
            if any(char in folder_name for char in "\[]}{\\$&%#@)()+!^."):
                return errorResponse("Folder name contains characters only.")
                
        if shared_type != 'Yes' and shared_type != 'No':
            return errorResponse(
                'Share must be only "Yes" or "No".'
            )
        folder_name = folder_name[:20].strip() if len(folder_name) > 20 else folder_name
        is_exist = db.query(Folder).filter(Folder.name == folder_name).filter(Folder.user_id == user.user_id).first()
        if is_exist: 
            return errorResponse(
                "Folder name already exist. Please use another folder name."
            )
        
        existing_folder.name = folder_name
        existing_folder.shared = shared_type
        # existing_folder.parent_id = folder.parent_id
        db.commit()
        updated_data = db.query(Folder).filter(Folder.folder_id == folder_id).filter(Folder.user_id == user.user_id).first()
        db.refresh(updated_data)
        # return existing_folder
        return successReponse(
            "Folder successfully updated.",
            schemas.FolderResponse.from_orm(updated_data).dict()
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")

# Delete a folders
@router.delete("/delete/{folder_id}")
async def delete_folder(folder_id: int, credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(dbase.get_db)):
    token = credentials.credentials
    user = auth.get_current_user(db, token)
    try:
        delete_folder = db.query(Folder).filter(Folder.folder_id == folder_id).filter(Folder.user_id == user.user_id).first()
        if not delete_folder:
            return errorResponse(
                "Folder not found"
            )
        chroma_dir_name = str(DB_FOLDER)+str(user.user_code)+'/'+str(delete_folder.sanitized_name)
        storage_dir_name = str(UPLOAD_FOLDER)+str(user.user_code)+'/'+str(delete_folder.sanitized_name)
        
        # Recursively delete the directory
        if os.path.exists(chroma_dir_name):
            shutil.rmtree(chroma_dir_name)
        if os.path.exists(storage_dir_name):
            shutil.rmtree(storage_dir_name)

        # if delete_folder.parent_id == 0:
        #     return errorResponse(
        #         "This folder can not allow to delete."
        #     )
        folder_documents = db.query(Documents).filter(Documents.folder_id == folder_id).all()
        for docs in folder_documents:
            db.delete(docs)
            db.commit()
            
        db.delete(delete_folder)
        db.commit()
        return successReponse(
            "Folder deleted successfully",
            None
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Something went wrong: {str(e)}")
