"""
Nextcloud Upload Script
Upload files and folders to Nextcloud using WebDAV protocol
"""

import os
import requests
from pathlib import Path
from typing import Union


class NextcloudUploader:
    def __init__(self, nextcloud_url: str, username: str, app_password: str):
        """
        Initialize Nextcloud uploader
        
        Args:
            nextcloud_url: Your Nextcloud server URL (e.g., 'https://cloud.example.com')
            username: Your Nextcloud username
            app_password: Your Nextcloud app password
        """
        self.nextcloud_url = nextcloud_url.rstrip('/')
        self.webdav_url = f"{self.nextcloud_url}/remote.php/dav/files/{username}"
        self.auth = (username, app_password)
        
    def create_folder(self, remote_path: str) -> bool:
        """
        Create a folder on Nextcloud
        
        Args:
            remote_path: Path on Nextcloud (e.g., '/inputs/folder1')
            
        Returns:
            True if successful, False otherwise
        """
        remote_path = remote_path.lstrip('/')
        url = f"{self.webdav_url}/{remote_path}"
        
        try:
            response = requests.request('MKCOL', url, auth=self.auth)
            if response.status_code in [201, 405]:  # 201 = created, 405 = already exists
                print(f"✓ Folder created/exists: {remote_path}")
                return True
            else:
                print(f"✗ Failed to create folder: {response.status_code}")
                return False
        except Exception as e:
            print(f"✗ Error creating folder: {e}")
            return False
    
    def upload_file(self, local_file_path: str, remote_path: str) -> bool:
        """
        Upload a single file to Nextcloud
        
        Args:
            local_file_path: Path to local file
            remote_path: Destination path on Nextcloud (e.g., '/inputs/folder1/file.txt')
            
        Returns:
            True if successful, False otherwise
        """
        remote_path = remote_path.lstrip('/')
        url = f"{self.webdav_url}/{remote_path}"
        
        try:
            with open(local_file_path, 'rb') as f:
                response = requests.put(url, data=f, auth=self.auth)
                
            if response.status_code in [201, 204]:  # 201 = created, 204 = updated
                print(f"✓ Uploaded: {local_file_path} -> {remote_path}")
                return True
            else:
                print(f"✗ Failed to upload {local_file_path}: {response.status_code}")
                return False
        except Exception as e:
            print(f"✗ Error uploading {local_file_path}: {e}")
            return False
    
    def upload_folder(self, local_folder_path: str, remote_base_path: str) -> bool:
        """
        Upload an entire folder (including subfolders) to Nextcloud
        
        Args:
            local_folder_path: Path to local folder
            remote_base_path: Destination base path on Nextcloud (e.g., '/inputs')
            
        Returns:
            True if successful, False otherwise
        """
        local_folder = Path(local_folder_path)
        
        if not local_folder.exists():
            print(f"✗ Local folder does not exist: {local_folder_path}")
            return False
        
        # Get folder name
        folder_name = local_folder.name
        remote_base_path = remote_base_path.rstrip('/')
        
        # Create base folder
        self.create_folder(f"{remote_base_path}/{folder_name}")
        
        # Walk through all files and subfolders
        for root, dirs, files in os.walk(local_folder):
            root_path = Path(root)
            
            # Calculate relative path from local_folder
            relative_path = root_path.relative_to(local_folder.parent)
            
            # Create subdirectories on Nextcloud
            for dir_name in dirs:
                remote_dir = f"{remote_base_path}/{relative_path}/{dir_name}"
                self.create_folder(remote_dir)
            
            # Upload files
            for file_name in files:
                local_file = root_path / file_name
                remote_file = f"{remote_base_path}/{relative_path}/{file_name}"
                self.upload_file(str(local_file), remote_file)
        
        print(f"\n✓ Folder upload complete: {local_folder_path} -> {remote_base_path}/{folder_name}")
        return True


# Example usage
if __name__ == "__main__":
    # Configuration
    NEXTCLOUD_URL = "https://your-nextcloud-server.com"  # Replace with your Nextcloud URL
    USERNAME = "your_username"  # Replace with your username
    APP_PASSWORD = "your_app_password"  # Replace with your app password
    
    # Initialize uploader
    uploader = NextcloudUploader(NEXTCLOUD_URL, USERNAME, APP_PASSWORD)
    
    # Example 1: Upload a single file
    # uploader.upload_file("local_file.txt", "/inputs/folder1/file.txt")
    
    # Example 2: Upload an entire folder
    # uploader.upload_folder("./my_local_folder", "/inputs")
    # This will create /inputs/my_local_folder/ on Nextcloud with all contents
    
    # Example 3: Create a folder first, then upload files
    # uploader.create_folder("/inputs/folder1")
    # uploader.upload_file("data.csv", "/inputs/folder1/data.csv")
