#!/usr/bin/env python3

import argparse
import os
import re
import shutil
import sys

# デフォルトのソースパス。環境に合わせて変更してください。
COE_tkProg_source = r"\\192.168.27.2\share\apps\tkProg\tklib"
COE_tkProg_dest   = "tklib"

# 拒否するパスの正規表現文字列のリスト
reject_patterns = [
#    r"__pycache__$",
#    r"\.pyc$",
#    r"\.prev$",
#    r"\.junk$",
#    r" - コピー",
#    r"kamiya",
#    r"personal",
]

def parse_args():
    """
    コマンドライン引数を解析する
    """
    parser = argparse.ArgumentParser(
        description="Recursively copy or sync files from source to destination, skipping rejected patterns."
    )
    parser.add_argument(
        "-s", "--source",
        type=str, default=COE_tkProg_source,
        help="Source directory to copy files from"
    )
    parser.add_argument(
        "-d", "--dest",
        type=str, default=COE_tkProg_dest,
        help="Destination directory to copy files to"
    )
    parser.add_argument(
        "-m", "--maxlevel",
        type=int, default=-1,
        help="Maximum recursion depth. 0 for no recursion, -1 for infinite (default), N for N levels."
    )
    return parser.parse_args()

def handle_user_choice(prompt):
    """
    ユーザーに選択肢を提示し、有効な入力を待つ
    """
    print(prompt)
    print("Options: [Y]es, [N]o, [A]ll, [R]etain All, [S]top")
    while True:
        choice = input("Your choice (y/n/a/r/s): ").lower()
        if choice in ['y', 'n', 'a', 'r', 's']:
            return choice
        print("Invalid input, please enter 'y', 'n', 'a', 'r', or 's'.")

def should_reject(path, compiled_patterns):
    """
    パスが拒否パターンに一致するかをチェックする
    """
    return any(pattern.search(path) for pattern in compiled_patterns)

def perform_copy(source, dest, compiled_patterns, maxlevel):
    """
    ファイルを再帰的にコピーする
    """
    global_user_choice = None
    source_root_depth = source.rstrip(os.sep).count(os.sep)

    print("\n[Phase 1] Copying/updating files from source to destination...")
    for root, dirs, files in os.walk(source):
        current_depth = root.rstrip(os.sep).count(os.sep) - source_root_depth

        if maxlevel != -1 and current_depth > maxlevel:
            del dirs[:]
            continue

        dirs[:] = [d for d in dirs if not should_reject(d, compiled_patterns)]

        rel_dir = os.path.relpath(root, source)
        dest_dir = os.path.join(dest, rel_dir) if rel_dir != "." else dest
        os.makedirs(dest_dir, exist_ok=True)
        
        dest_items_to_check = set(os.listdir(dest_dir)) if os.path.isdir(dest_dir) else set()
        for item in dest_items_to_check:
            if should_reject(item, compiled_patterns):
                dest_path = os.path.join(dest_dir, item)
                
                if global_user_choice == 'a':
                    if os.path.isdir(dest_path):
                        shutil.rmtree(dest_path)
                    else:
                        os.remove(dest_path)
                    print(f"Deleted '{dest_path}' (All mode).")
                    continue
                elif global_user_choice == 'r':
                    print(f"Kept '{dest_path}' (Retain All mode).")
                    continue
                
                prompt = f"'{dest_path}' matches a reject pattern. Delete it?"
                choice = handle_user_choice(prompt)
                
                if choice == 'y':
                    if os.path.isdir(dest_path):
                        shutil.rmtree(dest_path)
                    else:
                        os.remove(dest_path)
                    print(f"Deleted '{dest_path}'.")
                elif choice == 'n':
                    print(f"Kept '{dest_path}'.")
                elif choice == 'a':
                    global_user_choice = 'a'
                    if os.path.isdir(dest_path):
                        shutil.rmtree(dest_path)
                    else:
                        os.remove(dest_path)
                    print(f"Deleted '{dest_path}' and will delete all subsequent rejected items.")
                elif choice == 'r':
                    global_user_choice = 'r'
                    print(f"Kept '{dest_path}' and will retain all subsequent rejected items.")
                elif choice == 's':
                    print("Stopping program.")
                    sys.exit(0)
        
        for name in files:
            src_path = os.path.join(root, name)
            dest_path = os.path.join(dest_dir, name)
            
            if should_reject(name, compiled_patterns):
                continue
                
            if not os.path.exists(dest_path) or os.path.getmtime(src_path) > os.path.getmtime(dest_path):
                shutil.copy2(src_path, dest_path)
                print(f"Copied '{src_path}' to '{dest_path}'.")


def main():
    """
    メイン関数
    """
    args = parse_args()
    source = os.path.abspath(args.source)
    dest = os.path.abspath(args.dest)
    
    print(f"\nStarting file copy from '{source}' to '{dest}' with maxlevel={args.maxlevel}")

    if not os.path.isdir(source):
        print(f"Error: Source '{source}' is not a directory.")
        sys.exit(1)
        
    compiled_patterns = [re.compile(p) for p in reject_patterns]

    perform_copy(source, dest, compiled_patterns, args.maxlevel)


if __name__ == "__main__":
    main()