import os
import requests
from requests.auth import HTTPBasicAuth

def upload_folder_to_webdav(local_folder_path, remote_webdav_path, webdav_url, username, password, exclude_patterns=None):
    """
    将本地文件夹中的所有文件复制到指定的WebDAV路径，支持排除指定目录和文件
    
    Args:
        local_folder_path (str): 本地文件夹路径
        remote_webdav_path (str): WebDAV上的目标路径
        webdav_url (str): WebDAV服务器URL
        username (str): WebDAV用户名
        password (str): WebDAV密码
        exclude_patterns (list): 要排除的目录或文件名列表，默认排除 ['.git', '.DS_Store']
    
    Returns:
        bool: 上传成功返回True，否则返回False
    """
    
    # 默认排除列表
    if exclude_patterns is None:
        exclude_patterns = ['.git', '.DS_Store', '__pycache__', '.svn', '.hg']
    
    # 检查本地文件夹是否存在
    if not os.path.exists(local_folder_path):
        print(f"本地文件夹 {local_folder_path} 不存在")
        return False
        
    if not os.path.isdir(local_folder_path):
        print(f"{local_folder_path} 不是一个文件夹")
        return False
    
    print(f"开始上传文件夹 {local_folder_path} 到 {webdav_url}{remote_webdav_path}")
    print(f"排除模式: {exclude_patterns}")
    
    # 遍历本地文件夹中的所有文件和子文件夹
    for root, dirs, files in os.walk(local_folder_path):
        # 过滤目录，移除需要排除的目录
        dirs[:] = [d for d in dirs if d not in exclude_patterns]
        
        # 过滤文件，移除需要排除的文件
        files = [f for f in files if f not in exclude_patterns]
        
        # 计算相对路径
        relative_path = os.path.relpath(root, local_folder_path)
        if relative_path == ".":
            relative_path = ""
            
        # 创建远程路径
        if relative_path:
            remote_dir_path = os.path.join(remote_webdav_path, relative_path).replace("\\", "/")
        else:
            remote_dir_path = remote_webdav_path
            
        # 确保远程目录存在
        if not create_webdav_directory(remote_dir_path, webdav_url, username, password):
            print(f"创建远程目录 {remote_dir_path} 失败")
            continue
            
        # 上传文件
        for file in files:
            local_file_path = os.path.join(root, file)
            # 计算远程文件路径
            if relative_path:
                remote_file_path = os.path.join(remote_webdav_path, relative_path, file).replace("\\", "/")
            else:
                remote_file_path = os.path.join(remote_webdav_path, file).replace("\\", "/")
                
            if not upload_file_to_webdav(local_file_path, remote_file_path, webdav_url, username, password):
                print(f"上传文件 {local_file_path} 失败")
                continue
                
    print(f"文件夹 {local_folder_path} 上传完成")
    return True

def create_webdav_directory(remote_dir_path, webdav_url, username, password):
    """
    在WebDAV上创建目录
    
    Args:
        remote_dir_path (str): WebDAV上的目录路径
        webdav_url (str): WebDAV服务器URL
        username (str): WebDAV用户名
        password (str): WebDAV密码
    
    Returns:
        bool: 创建成功返回True，否则返回False
    """
    try:
        response = requests.request("MKCOL", f"{webdav_url}{remote_dir_path}", 
                                  auth=HTTPBasicAuth(username, password))
        # 201表示创建成功，405表示目录已存在
        if response.status_code in [201, 405]:
            return True
        else:
            # 忽略目录已存在的错误
            if response.status_code == 405:
                return True
            print(f"创建目录 {remote_dir_path} 失败: {response.status_code}")
            return False
    except Exception as e:
        print(f"创建目录 {remote_dir_path} 时出错: {e}")
        return False

def upload_file_to_webdav(local_file_path, remote_file_path, webdav_url, username, password):
    """
    上传单个文件到WebDAV
    
    Args:
        local_file_path (str): 本地文件路径
        remote_file_path (str): WebDAV上的文件路径
        webdav_url (str): WebDAV服务器URL
        username (str): WebDAV用户名
        password (str): WebDAV密码
    
    Returns:
        bool: 上传成功返回True，否则返回False
    """
    try:
        # 先删除WebDAV上同名文件（如果存在）
        delete_from_webdav(remote_file_path, webdav_url, username, password)
        
        with open(local_file_path, 'rb') as f:
            response = requests.put(
                f"{webdav_url}{remote_file_path}",
                data=f,
                auth=HTTPBasicAuth(username, password)
            )
            if response.status_code in [201, 204]:
                print(f"文件 {local_file_path} 上传成功到 {remote_file_path}")
                return True
            else:
                print(f"文件 {local_file_path} 上传失败: {response.status_code} {response.text}")
                return False
    except Exception as e:
        print(f"上传文件 {local_file_path} 时出错: {e}")
        return False

def delete_from_webdav(remote_path, webdav_url, username, password):
    """
    从WebDAV删除文件
    
    Args:
        remote_path (str): WebDAV上的文件路径
        webdav_url (str): WebDAV服务器URL
        username (str): WebDAV用户名
        password (str): WebDAV密码
    
    Returns:
        bool: 删除成功或文件不存在返回True，否则返回False
    """
    try:
        response = requests.delete(
            f"{webdav_url}{remote_path}",
            auth=HTTPBasicAuth(username, password)
        )
        # 204表示删除成功，404表示文件不存在（也认为是成功）
        if response.status_code in [204, 404]:
            return True
        else:
            # 忽略删除失败（可能文件不存在）
            return True
    except Exception as e:
        print(f"删除文件 {remote_path} 时出错: {e}")
        return False

# 使用示例
if __name__ == "__main__":
    # 配置参数
    local_folder = "../tvbox"  # 本地文件夹路径
    remote_path = "/home/TVBox/Private/tvbox"  # WebDAV目标路径
    webdav_url = "http://47.106.254.96:9120/dav"  # WebDAV服务器URL
    username = "lwang"  # 用户名
    password = "lw19971017"  # 密码
    
    # 排除列表
    exclude_list = ['.git', '.DS_Store', '__pycache__', '.svn', '.hg', 'node_modules']
    
    # 执行上传
    upload_folder_to_webdav(local_folder, remote_path, webdav_url, username, password, exclude_list)