# import os
# import time
# import requests
# from watchdog.observers import Observer
# from watchdog.events import FileSystemEventHandler
# import cloudinary
# from cloudinary import uploader, api

# # Configure Cloudinary with your credentials
# cloudinary.config(
#     cloud_name='df667rfp2',

#     # cloud_name='dhuti2qu7',

#         api_key='843839891244491',

#     # api_key='538825812971112',

#         api_secret='GUjP1I7lpjrig5Z7IXOF0WDzOyo'

#     # api_secret='HDbeJCSBUvoHhnyclj7aF_NW5a0'
# )

# local_folder_path = 'public/uploads'
# cloudinary_folder_path = 'public/uploads'  # Change this to your Cloudinary folder path

# def is_online():
#     try:
#         requests.get('http://www.google.com', timeout=5)
#         return True
#     except requests.RequestException:
#         return False

# def get_all_local_files(base_path):
#     all_files = []
#     for root, dirs, files in os.walk(base_path):
#         for file in files:
#             all_files.append(os.path.join(root, file))
#     return all_files

# def get_cloudinary_files(cloudinary_folder):
#     cloudinary_files = api.resources(type="upload", prefix=cloudinary_folder, max_results=500)
#     return [item['public_id'] for item in cloudinary_files['resources']]

# def are_folders_synced(local_folder, cloudinary_folder):
#     local_files = set(get_all_local_files(local_folder))
#     cloudinary_files = set(get_cloudinary_files(cloudinary_folder))
#     return local_files == cloudinary_files


# # def upload_files_to_cloudinary(local_folder, cloudinary_folder):
# #     local_files = get_all_local_files(local_folder)
# #     local_files_relative = [os.path.relpath(file, local_folder) for file in local_files]

# #     for file_path, relative_path in zip(local_files, local_files_relative):
# #         cloudinary_file_path = os.path.join(cloudinary_folder, relative_path).replace("\\", "/")
# #         try:
# #             uploader.upload(file_path, public_id=cloudinary_file_path)
# #             print(f'Uploaded {relative_path} to Cloudinary')
# #         except Exception as e:
# #             print(f'Error uploading {relative_path}: {e}')





# def upload_files_to_cloudinary(local_folder, cloudinary_folder):
#     local_files = get_all_local_files(local_folder)
#     local_files_relative = [os.path.relpath(file, local_folder) for file in local_files]

#     for file_path, relative_path in zip(local_files, local_files_relative):
#         cloudinary_file_path = os.path.join(cloudinary_folder, relative_path).replace("\\", "/")
        
#         # Determine the resource type
#         resource_type = 'image'
#         if file_path.lower().endswith(('.xlsx', '.xls', '.csv', '.txt', '.pdf')):
#             resource_type = 'raw'

#         try:
#             uploader.upload(file_path, public_id=cloudinary_file_path, resource_type=resource_type)
#             print(f'Uploaded {relative_path} to Cloudinary as {resource_type}')
#         except Exception as e:
#             print(f'Error uploading {relative_path}: {e}')

# def download_files_from_cloudinary(local_folder, cloudinary_folder):
#     cloudinary_files = api.resources(type="upload", prefix=cloudinary_folder, max_results=500)

#     for item in cloudinary_files['resources']:
#         cloudinary_file_path = item['public_id']
#         relative_path = os.path.relpath(cloudinary_file_path, cloudinary_folder)
#         local_file_path = os.path.join(local_folder, relative_path)

#         if not os.path.exists(local_file_path):
#             cloudinary_url = cloudinary.utils.cloudinary_url(cloudinary_file_path)[0]
#             os.makedirs(os.path.dirname(local_file_path), exist_ok=True)
#             try:
#                 response = requests.get(cloudinary_url)
#                 if response.status_code == 200:
#                     with open(local_file_path, 'wb') as file:
#                         file.write(response.content)
#                     print(f'Downloaded {relative_path} from Cloudinary')
#                 else:
#                     print(f'Failed to download {relative_path}: Status Code {response.status_code}')
#             except Exception as e:
#                 print(f'Error downloading {relative_path}: {e}')

# class FileEventHandler(FileSystemEventHandler):
#     def __init__(self, sync_function):
#         self.sync_function = sync_function

#     def on_any_event(self, event):
#         if event.is_directory:
#             return
#         self.sync_function()

# def sync_folders():
#     if is_online():
#         upload_files_to_cloudinary(local_folder_path, cloudinary_folder_path)
#         download_files_from_cloudinary(local_folder_path, cloudinary_folder_path)
#     else:
#         print("Currently offline. Monitoring for file changes.")

# def main():
#     event_handler = FileEventHandler(sync_folders)
#     observer = Observer()
#     observer.schedule(event_handler, local_folder_path, recursive=True)
#     observer.start()

#     try:
#         while True:
#             time.sleep(5)
#             sync_folders()
#     except KeyboardInterrupt:
#         observer.stop()
#         observer.join()

# if __name__ == "__main__":
#     main()







import os
import time
import requests
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import cloudinary
from cloudinary import uploader, api
from datetime import datetime
from dateutil import parser

# Configure Cloudinary with your credentials
cloudinary.config(
    cloud_name='df667rfp2',
    api_key='843839891244491',
    api_secret='GUjP1I7lpjrig5Z7IXOF0WDzOyo'
)

local_folder_path = 'public/uploads'
cloudinary_folder_path = 'public/uploads'  # Change this to your Cloudinary folder path

def is_online():
    try:
        requests.get('http://www.google.com', timeout=5)
        return True
    except requests.RequestException:
        return False

def get_all_local_files(base_path):
    all_files = []
    for root, dirs, files in os.walk(base_path):
        for file in files:
            all_files.append(os.path.join(root, file))
    return all_files

def file_needs_upload(local_file_path, cloudinary_file_path):
    if not os.path.exists(local_file_path):
        return False

    try:
        cloudinary_file = uploader.explicit(cloudinary_file_path, type='upload')
        cloudinary_mod_time = parser.isoparse(cloudinary_file['created_at']).replace(tzinfo=None)
        local_mod_time = datetime.fromtimestamp(os.path.getmtime(local_file_path))
        return local_mod_time > cloudinary_mod_time
    except cloudinary.exceptions.Error:
        return True

def upload_files_to_cloudinary(local_folder, cloudinary_folder):
    local_files = get_all_local_files(local_folder)
    local_files_relative = [os.path.relpath(file, local_folder) for file in local_files]

    for file_path, relative_path in zip(local_files, local_files_relative):
        cloudinary_file_path = os.path.join(cloudinary_folder, relative_path).replace("\\", "/")
        resource_type = 'raw'  # Upload all file types as raw

        if file_needs_upload(file_path, cloudinary_file_path):
            try:
                uploader.upload(file_path, public_id=cloudinary_file_path, resource_type=resource_type)
                print(f'Uploaded {relative_path} to Cloudinary as {resource_type}')
            except Exception as e:
                print(f'Error uploading {relative_path}: {e}')
        else:
            print(f"{file_path} is already up-to-date on Cloudinary.")

def file_needs_download(local_file_path, cloudinary_file_info):
    if not os.path.exists(local_file_path):
        return True

    local_mod_time = os.path.getmtime(local_file_path)
    cloudinary_mod_time = parser.parse(cloudinary_file_info['created_at'])
    return local_mod_time < cloudinary_mod_time.timestamp()

# def download_files_from_cloudinary(local_folder, cloudinary_folder):
#     cloudinary_files = api.resources(type="upload", prefix=cloudinary_folder, max_results=500, resource_type='raw')
#     for item in cloudinary_files['resources']:
#         cloudinary_file_path = item['public_id']
#         relative_path = os.path.relpath(cloudinary_file_path, cloudinary_folder)
#         local_file_path = os.path.join(local_folder, relative_path)

#         if file_needs_download(local_file_path, item):
#             cloudinary_url = cloudinary.utils.cloudinary_url(cloudinary_file_path)[0]
#             os.makedirs(os.path.dirname(local_file_path), exist_ok=True)
#             try:
#                 response = requests.get(cloudinary_url)
#                 if response.status_code == 200:
#                     with open(local_file_path, 'wb') as file:
#                         file.write(response.content)
#                     print(f'Downloaded {relative_path} from Cloudinary')
#                 else:
#                     print(f'Failed to download {relative_path}: Status Code {response.status_code}')
#             except Exception as e:
#                 print(f'Error downloading {relative_path}: {e}')
#         else:
#             print(f"{local_file_path} is already up-to-date locally.")






def download_files_from_cloudinary(local_folder, cloudinary_folder):
    # Requesting raw resources from Cloudinary
    cloudinary_files = api.resources(type="upload", prefix=cloudinary_folder, max_results=500, resource_type='raw')

    for item in cloudinary_files['resources']:
        cloudinary_file_path = item['public_id']
        relative_path = os.path.relpath(cloudinary_file_path, cloudinary_folder)
        local_file_path = os.path.join(local_folder, relative_path)

        if file_needs_download(local_file_path, item):
            # Retrieving the raw file URL
            cloudinary_url = cloudinary.utils.cloudinary_url(cloudinary_file_path, resource_type='raw')[0]
            os.makedirs(os.path.dirname(local_file_path), exist_ok=True)
            try:
                response = requests.get(cloudinary_url)
                if response.status_code == 200:
                    with open(local_file_path, 'wb') as file:
                        file.write(response.content)
                    print(f'Downloaded {relative_path} from Cloudinary')
                else:
                    print(f'Failed to download {relative_path}: Status Code {response.status_code}')
            except Exception as e:
                print(f'Error downloading {relative_path}: {e}')
        else:
            print(f"{local_file_path} is already up-to-date locally.")


class FileEventHandler(FileSystemEventHandler):
    def __init__(self, sync_function):
        self.sync_function = sync_function

    def on_any_event(self, event):
        if event.is_directory:
            return
        self.sync_function()

def sync_folders():
    if is_online():
        upload_files_to_cloudinary(local_folder_path, cloudinary_folder_path)
        download_files_from_cloudinary(local_folder_path, cloudinary_folder_path)
    else:
        print("Currently offline. Monitoring for file changes.")

def main():
    event_handler = FileEventHandler(sync_folders)
    observer = Observer()
    observer.schedule(event_handler, local_folder_path, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(5)
            sync_folders()
    except KeyboardInterrupt:
        observer.stop()
        observer.join()

if __name__ == "__main__":
    main()
