import gradio as gr
import os
import shutil
from pymongo.mongo_client import MongoClient
from pymongo.server_api import ServerApi
import urllib.parse
from bson.objectid import ObjectId

username = urllib.parse.quote_plus(os.getenv('MONGO_USERNAME'))
password = urllib.parse.quote_plus(os.getenv('MONGO_PASSWORD'))
restUri = os.getenv('REST_URI')
uri = f'mongodb+srv://{username}:{password}{restUri}'
client = MongoClient(uri, server_api=ServerApi('1'))
db = client['file_storage']
references_collection = db['references']

try:
    client.admin.command('ping')
    print("Pinged your deployment. You successfully connected to MongoDB!")
except Exception as e:
    print(e)

theme = gr.themes.Default(
    primary_hue="blue",
    secondary_hue="violet",
    neutral_hue="slate",
).set(
    button_secondary_background_fill='*secondary_200',
    button_secondary_background_fill_hover='*secondary_300',
    button_secondary_background_fill_dark='*secondary_600',
    button_secondary_background_fill_hover_dark='*secondary_500',
    button_secondary_border_color='*secondary_200',
    button_secondary_border_color_hover='*secondary_300',
    button_secondary_border_color_dark='*secondary_600',
    button_secondary_border_color_hover_dark='*secondary_500',
    button_secondary_text_color='*secondary_700'
)

def upload(file, secret):
    if secret == os.environ.get('SECRET_KEY'):
        root_directory = '/tmp/gradio'
        folder_contents_dict = get_folder_contents_dict(root_directory)
        base_url = "https://abhicodes-file-sharing-system.hf.space/file=/tmp/gradio"
        urls = [f"{base_url}/{folder}/{file}" for folder, files in folder_contents_dict.items() for file in files]
        references_collection.update_one({"_id": ObjectId('66531a797cbaa19ba4e441c5')}, {"$set": {"urls": urls}})

        gr.Info("Uploaded Successfully")
    
    else:
        for ele in file:
            dir_to_remove = os.path.dirname(ele)
            shutil.rmtree(dir_to_remove)
        
        gr.Warning("Unauthorized to upload")

def get_folder_contents_dict(root_dir):
    folder_contents = {}
    for item in os.listdir(root_dir):
        item_path = os.path.join(root_dir, item)
        if os.path.isdir(item_path):
            contents = os.listdir(item_path)
            folder_contents[item] = contents
    
    return folder_contents

def generate_markdown(json_data):
    urls = json_data.get("urls", [])
    markdown_lines = []
    count = 1
    for url in urls:
        encoded_url = urllib.parse.quote(url, safe=':/')
        filename = url.split('/')[-1]
        encoded_filename = urllib.parse.quote(filename).replace("%20", " ")
        markdown_lines.append(f'> {count}. <a style="text-decoration:none;" href={encoded_url} target="_blank">{encoded_filename}</a>')
        count += 1
    return "\n".join(markdown_lines)

def get_uploads(secret):
    if secret == os.environ.get('SECRET_KEY'):
        result = references_collection.find_one({"_id": ObjectId('66531a797cbaa19ba4e441c5')}, {"_id": 0})
        if result:
            markdown_output = generate_markdown(result)
            gr.Info("Recieved uploaded files")
            return markdown_output
        else:
            return '''<p style="color:red;font-size:20px;text-align:center;font-weight:bold;">No result found</p>'''
    else:
        return '''<p style="color:red;font-size:20px;text-align:center;font-weight:bold;">Invalid Secret Key</p>'''

def get_notes(secret):
    if secret == os.environ.get('SECRET_KEY'):
        result = references_collection.find_one({"_id": ObjectId('6655fe4ca6913aa201819e72')}, {"_id": 0})
        if result:
            gr.Info("Recieved shared notes")
            return result['notes']
        else:
            gr.Info("No result found")
            return '''No result found'''
    else:
        gr.Warning("Invalid Secret Key")
        return '''Invalid Secret Key'''

def save_notes(note, secret):
    if secret == os.environ.get('SECRET_KEY'):
        result = references_collection.update_one({"_id": ObjectId('6655fe4ca6913aa201819e72')}, {"$set": {"notes": note}})
        if result:
            gr.Info("Notes saved successfully.")
            return note
        else:
            gr.Info("No result found")
            return '''No result found'''
    else:
        gr.Warning("Invalid Secret Key")
        return note

def delete_path(path):
    try:
        if os.path.isfile(path):
            os.remove(path)
            filename = os.path.basename(path)
            root_directory = '/tmp/gradio'
            folder_contents_dict = get_folder_contents_dict(root_directory)
            base_url = "https://abhicodes-file-sharing-system.hf.space/file=/tmp/gradio"
            urls = [f"{base_url}/{folder}/{file}" for folder, files in folder_contents_dict.items() for file in files]
            references_collection.update_one({"_id": ObjectId('66531a797cbaa19ba4e441c5')}, {"$set": {"urls": urls}})
            gr.Info(f"The file {filename} has been deleted successfully.")
        elif os.path.isdir(path):
            shutil.rmtree(path)
            foldername = os.path.basename(path)
            root_directory = '/tmp/gradio'
            folder_contents_dict = get_folder_contents_dict(root_directory)
            base_url = "https://abhicodes-file-sharing-system.hf.space/file=/tmp/gradio"
            urls = [f"{base_url}/{folder}/{file}" for folder, files in folder_contents_dict.items() for file in files]
            references_collection.update_one({"_id": ObjectId('66531a797cbaa19ba4e441c5')}, {"$set": {"urls": urls}})
            gr.Info(f"The directory {foldername} has been deleted successfully.")
        else:
            print(f"The path {path} does not exist.")
            gr.Warning("Invalid action.")
    except Exception as e:
        print(f"An error occurred while deleting {path}: {e}")
        gr.Warning("Invalid action.")


def delete_files(path, secret):
    if secret == os.environ.get('SECRET_KEY'):
        for paths in path:
            delete_path(paths)
    else:
        gr.Warning("Invalid Secret Key")

    return gr.update(root_dir="/tmp/gradio")

def toogle_visibility(secret):
    if secret == os.environ.get('SECRET_KEY'):
        return gr.update(visible=False), gr.update(visible=True), gr.update(visible=True)
    else:
        raise gr.Error("Invalid Secret Key")

def toogle_vis():
    return gr.update(visible=True)

def toogle_vis2():
    return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)

js = '''
function test() {
    document.title = "File Sharing System";
    var link = document.createElement('link');
    link.type = 'image/x-icon';
    link.rel = 'shortcut icon';
    link.href = 'https://cdn3d.iconscout.com/3d/premium/thumb/cloud-storage-5402862-4521475.png';
    document.getElementsByTagName('head')[0].appendChild(link);
    var manifest = document.createElement('link');
    manifest.rel = 'manifest';
    manifest.href = 'https://api.npoint.io/fdf723018418571a93a8';
    document.getElementsByTagName('head')[0].appendChild(manifest);

    function updateHeroContainerStyle() {
        if (window.innerWidth <= 600) {
            const ele = document.querySelector(".hero-container");
            if (ele) {
                ele.style.flexDirection = 'column';
                ele.style.padding = '5px';
                ele.style.margin = '0px';
                ele.style.gap = '0px';
            }
        }
        else {
            const ele = document.querySelector(".hero-container");
            if (ele) {
                ele.style.flexDirection = 'row';
                ele.style.padding = '5px';
                ele.style.margin = '0px 20px 0px 20px';
                ele.style.gap = '50px';
            }
        }
    }
    updateHeroContainerStyle();
    window.addEventListener('resize', updateHeroContainerStyle);
}
'''

css = '''
body::-webkit-scrollbar {
    display: none;
    scroll:smooth;
}
.hero-container {
    display: flex;
    flex-direction: row;
    gap:50px;
    justify-content: center;
    align-items: center;
    padding: 5px;
    border-radius: 10px;
    max-width: 100%;
    margin: 20px;
    margin-top: 0px;
    margin-bottom: 0px;
}
.logo {
    width: 80px;
}
.description {
    text-align: justify;
}
footer {
    visibility: hidden
}
'''

with gr.Blocks(theme=theme, js=js, css=css) as demo:
    gr.Markdown('''<h1 style="text-align:center;">File Storing and Sharing System</h1>''')
    with gr.Column():
        gr.Markdown(''' <div class="hero-container">
                            <img src="https://cdn3d.iconscout.com/3d/premium/thumb/cloud-storage-5402862-4521475.png" alt="logo" class="logo">
                            <p class="description">This project is a file storing and sharing system built using Gradio for the front-end interface and MongoDB for the back-end database. The system allows users to upload files, which are then stored and managed within a specified directory. URLs for accessing these files are generated and stored in a MongoDB collection, making it easy to share and access the uploaded files.</p>
                        </div> ''')    
        
    secret_key = gr.Text(label="🔐 Secret Key", placeholder="Enter your secret key here...", type="password", autofocus=True)
    with gr.Row():
        with gr.Column():
            gr.Markdown('''<h1 style="text-align:center;display:flex;justify-content:center;align-items:center"><img src="https://i.ibb.co/FB6tMdT/upload.png" alt="upload" width="50">Uploader</h1>''')
            input = gr.File(label="Upload", file_count="multiple")
            input.upload(fn=upload, inputs=[input, secret_key])
        with gr.Column():
            gr.Markdown('''<h1 style="text-align:center;display:flex;justify-content:center;align-items:center"><img src="https://i.ibb.co/K9Bq3j7/download.png" alt="download" width="50">Downloader</h1>''')
            uploads = gr.Markdown(label="Uploads")
            get_upload_button = gr.Button("Get Uploads", variant='primary')
            get_upload_button.click(fn=get_uploads, inputs=secret_key, outputs=uploads)
            initial_delete_button = gr.Button("Delete Uploads?", variant="stop", visible=True)
            cancel_button = gr.Button("Cancel", variant="secondary", visible=False)
        with gr.Column(visible=False) as temp:
            gr.Markdown('''<h1 style="text-align:center;display:flex;justify-content:center;align-items:center"><img src="https://i.ibb.co/K9Bq3j7/download.png" alt="download" width="50">Navigator</h1>''')
            file_exe = gr.FileExplorer(root_dir="/tmp/gradio")
            final_delete_button = gr.Button("Delete", variant="stop", visible=False)
            final_delete_button.click(fn=delete_files, inputs=[file_exe, secret_key], outputs=file_exe)
            file_exe.change(fn=toogle_vis, outputs=final_delete_button)
        initial_delete_button.click(fn=toogle_visibility, inputs=secret_key, outputs=[initial_delete_button, cancel_button, temp])
        cancel_button.click(fn=toogle_vis2, outputs=[temp, initial_delete_button, cancel_button])
        
            
    notes = gr.TextArea(label="📝 Share Notes", placeholder="Enter your notes...")
    with gr.Row():    
        get_notes_button = gr.Button("Get Notes", variant="secondary")
        get_notes_button.click(fn=get_notes, inputs=secret_key, outputs=notes)
        save_notes_button = gr.Button("Save", variant="primary")
        save_notes_button.click(fn=save_notes, inputs=[notes,secret_key], outputs=notes)

    gr.Markdown('''> To know more read the docs at: [Documentation](https://huggingface.co/spaces/abhicodes/file-sharing-system/blob/main/README.md)''')

demo.launch(debug=True)