"""
Config merge utility for incremental updates.

Preserves user edits in config.yaml while adding new configuration keys
introduced by source code updates.

Usage:
    python scripts/merge_config.py --old <user_config.yaml> --new <source_config.yaml> --output <merged.yaml>
"""
import argparse
import sys
from pathlib import Path
try:
    import yaml
except ImportError:
    # Fallback when running outside Django context
    try:
        import ruamel.yaml as yaml
    except ImportError:
        print("[ERROR] PyYAML is required. Install with: pip install pyyaml", file=sys.stderr)
        sys.exit(1)


def deep_merge(base: dict, overlay: dict) -> dict:
    """Merge overlay into base, preserving base values for existing keys.
    
    Rules:
    - Keys in base that are NOT in overlay: preserved unchanged
    - Keys in overlay that are NOT in base: added from overlay
    - Keys in BOTH: base value wins (user edits preserved)
    - Nested dicts: recursively merged with same rules
    - Lists/scalars: base wins entirely (no element-level merge)
    """
    result = dict(base)
    for k, v in overlay.items():
        if k not in result:
            # New key from update → take new value
            result[k] = v
        elif isinstance(v, dict) and isinstance(result.get(k), dict):
            # Both are dicts → recursive merge
            result[k] = deep_merge(result[k], v)
        # else: key exists in both → base wins (user edit preserved)
    return result


def merge_config(old_path: Path, new_path: Path, output_path: Path) -> int:
    """Merge old (user) config with new (source) config.
    
    Returns:
        0 on success, 1 on error
    """
    if not old_path.exists():
        print(f"[CONFIG] No user config at {old_path}, using source config directly")
        import shutil
        shutil.copy2(str(new_path), str(output_path))
        return 0
    
    if not new_path.exists():
        print(f"[ERROR] Source config {new_path} not found", file=sys.stderr)
        return 1
    
    try:
        with open(old_path, 'r', encoding='utf-8') as f:
            old = yaml.safe_load(f) or {}
    except Exception as e:
        print(f"[CONFIG_MERGE_FAILED] Cannot parse user config: {e}", file=sys.stderr)
        print("[CONFIG] Falling back to source config")
        import shutil
        shutil.copy2(str(new_path), str(output_path))
        return 0
    
    try:
        with open(new_path, 'r', encoding='utf-8') as f:
            new = yaml.safe_load(f) or {}
    except Exception as e:
        print(f"[ERROR] Cannot parse source config: {e}", file=sys.stderr)
        return 1
    
    merged = deep_merge(old, new)
    
    output_path.parent.mkdir(parents=True, exist_ok=True)
    with open(output_path, 'w', encoding='utf-8') as f:
        yaml.dump(merged, f, default_flow_style=False, allow_unicode=True)
    
    # Count preserved vs new keys
    preserved = sum(1 for k in merged if k in old)
    added = sum(1 for k in merged if k not in old)
    print(f"[CONFIG] Merged: {preserved} keys preserved, {added} keys added from update")
    return 0


def main():
    parser = argparse.ArgumentParser(description='Merge user config with source config for incremental updates')
    parser.add_argument('--old', required=True, help='Path to user config (existing, may have edits)')
    parser.add_argument('--new', required=True, help='Path to source config (from update package)')
    parser.add_argument('--output', required=True, help='Path to write merged config')
    args = parser.parse_args()
    
    sys.exit(merge_config(
        Path(args.old), Path(args.new), Path(args.output)
    ))


if __name__ == '__main__':
    main()
