import os
import sys
import logging
import paramiko
import ftpsync.targets
import ftpsync.sftp_target
from ftpsync.synchronizers import BiDirSynchronizer
from ftpsync.util import CliSilentRuntimeError

# --- 配置日誌記錄 (在函數外部配置，以便在函數呼叫前就生效) ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def ensure_sftp_folder_exists(
    remote_dir: str = '/storage/emulated/0/Download/360a/t7_py/t7/t716/send_system_info_email/',
    ssh_host: str = '192.168.85.222',
    ssh_username: str = 'u0_a454',
    ssh_password: str = 'Liteon@2022',
    ssh_port: int = 8022
):
    """
    確保遠端 SFTP 目錄存在，如不存在則遞迴創建。
    """
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(ssh_host, port=ssh_port, username=ssh_username, password=ssh_password)
    sftp = ssh.open_sftp()
    try:
        try:
            sftp.stat(remote_dir)
            logging.info(f"Directory exists: {remote_dir}")
        except IOError:
            logging.info(f"Directory does not exist, creating: {remote_dir}")
            dirs = remote_dir.strip("/").split("/")
            curr_dir = ""
            for d in dirs:
                curr_dir += "/" + d
                try:
                    sftp.stat(curr_dir)
                except IOError:
                    sftp.mkdir(curr_dir)
                    logging.info(f"Created directory: {curr_dir}")
    finally:
        sftp.close()
        ssh.close()

def run_sftp_sync(
    ssh_host: str = "192.168.85.222",
    ssh_username: str = "u0_a454",
    ssh_password: str = "Liteon@2022",
    ssh_port: int = 8022,
    path: str = "t7/t716/send_system_info_email/",
    local_dir_linux: str = "/home/frank/360a/t7_py/",
    local_dir_windows: str = "N:/OneDrive/私人文件，dengchunying1988/Documents/sb_py/",
    remote_dir: str = None,
    log_level: int = logging.INFO,
    sync_mode: str = "sync",
    sync_verbose: int = 5,
    sync_dry_run: bool = False,
    sync_delete: bool = False,
    sync_force: bool = False,
    sync_resolve: str = "remote",
    sync_ignore_passive_ip: bool = True,
    sync_no_verify_host_keys: bool = True,
    sync_exclude: str = ".DS_Store,.git,.hg,.svn,#recycle,frankyu/frankyu/t7/t7042/",
    sync_match: str = "*.py"
):
    """
    執行本地資料夾與 SFTP 伺服器的同步。
    所有參數均有預設值。
    """
    logging.getLogger().setLevel(log_level)
    if remote_dir is None:
        remote_dir = f"/storage/emulated/0/Download/360a/t7_py/{path}"

    # 根據作業系統確定本地路徑
    if sys.platform.startswith('win'):
        local_path = os.path.normpath(os.path.expandvars(os.path.join(local_dir_windows, path)))
        logging.info("檢測到 Windows 平台。")
    elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
        local_path = os.path.normpath(os.path.expanduser(os.path.join(local_dir_linux, path)))
        logging.info("檢測到 Linux 或 macOS 平台。")
    else:
        local_path = os.path.normpath(os.path.expandvars(os.path.join(local_dir_windows, path)))
        logging.warning(f"未知作業系統平台: {sys.platform}。使用默認 Windows 路徑。")
    
    sftp_url_display = f"sftp://{ssh_username}@{ssh_host}:{ssh_port}{remote_dir}" 
    logging.info(f"本地同步路徑: {local_path}")
    logging.info(f"遠端 SFTP 同步路徑: {sftp_url_display}")

    # 前置檢查
    if not os.path.exists(local_path):
        logging.error(f"錯誤: 本地資料夾 '{local_path}' 不存在。請創建它或檢查路徑。")
        sys.exit(1)
    if not os.access(local_path, os.R_OK | os.W_OK):
        logging.error(f"錯誤: 對本地資料夾 '{local_path}' 沒有讀取或寫入權限。請檢查權限設定。")
        sys.exit(1)

    local_target = None
    sftp_target = None

    try:
        local_target = ftpsync.targets.FsTarget(local_path)
        logging.info("本地目標創建成功。")
        sftp_target = ftpsync.sftp_target.SFTPTarget(
            path=remote_dir,
            host=ssh_host,
            port=ssh_port,
            username=ssh_username,
            password=ssh_password,
        )
        logging.info("遠端 SFTP 目標創建成功。")
        sync_options = {
            "mode": sync_mode,
            "verbose": sync_verbose,
            "dry_run": sync_dry_run,
            "delete": sync_delete,
            "force": sync_force,
            "resolve": sync_resolve,
            "ignore_passive_ip": sync_ignore_passive_ip,
            "no_verify_host_keys": sync_no_verify_host_keys,
            "exclude": sync_exclude,
            "match": sync_match,
        }
        sync = BiDirSynchronizer(local_target, sftp_target, sync_options)
        logging.info("開始執行資料夾同步...")
        result = sync.run()
        logging.info("資料夾同步完成！")
        logging.info(f"同步結果摘要: {result}")
        if result.get('errors'):
            logging.warning(f"同步過程中出現警告/錯誤: {result['errors']}")
    except CliSilentRuntimeError as e:
        logging.error(f"同步失敗：一個靜默運行時錯誤發生。錯誤訊息: {e}")
        sys.exit(1)
    except Exception as e:
        error_message = str(e).lower()
        if "authentication failed" in error_message or "permission denied" in error_message:
            logging.error(f"同步失敗：SFTP 認證失敗。請檢查使用者名、密碼或 SSH 金鑰。錯誤訊息: {e}")
        elif "no such file or directory" in error_message and "remote" in error_message:
            logging.error(f"同步失敗：遠端 SFTP 路徑可能不正確或沒有創建目錄的權限。請確保遠端目標路徑已存在。錯誤訊息: {e}")
        elif "timed out" in error_message or "connection refused" in error_message:
            logging.error(f"同步失敗：無法連接到 SFTP 伺服器。請檢查伺服器地址、埠號或網路連接。錯誤訊息: {e}")
        else:
            logging.error(f"同步過程中發生未知錯誤: {e}", exc_info=True)
    finally:
        if local_target and local_target.connected:
            local_target.close()
        if sftp_target and sftp_target.connected:
            sftp_target.close()

def run_sftp_sync(
    ssh_host = "192.168.85.222",
    ssh_username  = "u0_a454",
    ssh_password  = "Liteon@2022",
    ssh_port = 8022,
    path = "t7/t716/send_system_info_email/",
    local_dir_linux  = "/home/frank/360a/t7_py/",
    local_dir_windows  = "N:/OneDrive/私人文件，dengchunying1988/Documents/sb_py/",
    remote_dir  = None,
    log_level = logging.INFO,
    sync_mode  = "sync",
    sync_verbose  = 5,
    sync_dry_run  = False,
    sync_delete  = False,
    sync_force  = False,
    sync_resolve  = "remote",
    sync_ignore_passive_ip  = True,
    sync_no_verify_host_keys  = True,
    sync_exclude  = ".DS_Store,.git,.hg,.svn,#recycle,frankyu/frankyu/t7/t7042/",
    sync_match  = "*.py"
):
    """
    執行本地資料夾與 SFTP 伺服器的同步。
    所有參數均有預設值。
    """
    logging.getLogger().setLevel(log_level)
    if remote_dir is None:
        remote_dir = f"/storage/emulated/0/Download/360a/t7_py/{path}"

    # 根據作業系統確定本地路徑
    if sys.platform.startswith('win'):
        local_path = os.path.normpath(os.path.expandvars(os.path.join(local_dir_windows, path)))
        logging.info("檢測到 Windows 平台。")
    elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
        local_path = os.path.normpath(os.path.expanduser(os.path.join(local_dir_linux, path)))
        logging.info("檢測到 Linux 或 macOS 平台。")
    else:
        local_path = os.path.normpath(os.path.expandvars(os.path.join(local_dir_windows, path)))
        logging.warning(f"未知作業系統平台: {sys.platform}。使用默認 Windows 路徑。")
    
    sftp_url_display = f"sftp://{ssh_username}@{ssh_host}:{ssh_port}{remote_dir}" 
    logging.info(f"本地同步路徑: {local_path}")
    logging.info(f"遠端 SFTP 同步路徑: {sftp_url_display}")

    # 前置檢查
    if not os.path.exists(local_path):
        logging.error(f"錯誤: 本地資料夾 '{local_path}' 不存在。請創建它或檢查路徑。")
        sys.exit(1)
    if not os.access(local_path, os.R_OK | os.W_OK):
        logging.error(f"錯誤: 對本地資料夾 '{local_path}' 沒有讀取或寫入權限。請檢查權限設定。")
        sys.exit(1)

    local_target = None
    sftp_target = None

    try:
        local_target = ftpsync.targets.FsTarget(local_path)
        logging.info("本地目標創建成功。")
        sftp_target = ftpsync.sftp_target.SFTPTarget(
            path=remote_dir,
            host=ssh_host,
            port=ssh_port,
            username=ssh_username,
            password=ssh_password,
        )
        logging.info("遠端 SFTP 目標創建成功。")
        sync_options = {
            "mode": sync_mode,
            "verbose": sync_verbose,
            "dry_run": sync_dry_run,
            "delete": sync_delete,
            "force": sync_force,
            "resolve": sync_resolve,
            "ignore_passive_ip": sync_ignore_passive_ip,
            "no_verify_host_keys": sync_no_verify_host_keys,
            "exclude": sync_exclude,
            "match": sync_match,
        }
        sync = BiDirSynchronizer(local_target, sftp_target, sync_options)
        logging.info("開始執行資料夾同步...")
        result = sync.run()
        logging.info("資料夾同步完成！")
        logging.info(f"同步結果摘要: {result}")
        if result.get('errors'):
            logging.warning(f"同步過程中出現警告/錯誤: {result['errors']}")
    except CliSilentRuntimeError as e:
        logging.error(f"同步失敗：一個靜默運行時錯誤發生。錯誤訊息: {e}")
        sys.exit(1)
    except Exception as e:
        error_message = str(e).lower()
        if "authentication failed" in error_message or "permission denied" in error_message:
            logging.error(f"同步失敗：SFTP 認證失敗。請檢查使用者名、密碼或 SSH 金鑰。錯誤訊息: {e}")
        elif "no such file or directory" in error_message and "remote" in error_message:
            logging.error(f"同步失敗：遠端 SFTP 路徑可能不正確或沒有創建目錄的權限。請確保遠端目標路徑已存在。錯誤訊息: {e}")
        elif "timed out" in error_message or "connection refused" in error_message:
            logging.error(f"同步失敗：無法連接到 SFTP 伺服器。請檢查伺服器地址、埠號或網路連接。錯誤訊息: {e}")
        else:
            logging.error(f"同步過程中發生未知錯誤: {e}", exc_info=True)
    finally:
        if local_target and local_target.connected:
            local_target.close()
        if sftp_target and sftp_target.connected:
            sftp_target.close()

if __name__ == "__main__":
    # 先確保遠端目錄存在
    ensure_sftp_folder_exists()
    # 執行同步（所有參數都可以省略使用預設值，也可自訂）
    run_sftp_sync()