#!/usr/bin/env python3
"""Copy workshop mods from SERVER.xml into LocalMods/ with readable names."""

import shutil
import sys
import os
import xml.etree.ElementTree as ET

WORKSHOP_DIR = "/mnt/nvme/B/SteamLibrary/steamapps/workshop/content/602960"
MODLIST_PATH = "/mnt/nvme/B/SteamLibrary/steamapps/common/Barotrauma/ModLists/SERVER.xml"
LOCALMODS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "LocalMods")


def log_ok(msg: str, indent: int = 0):
    prefix = "  " * indent + "✓"
    print(f"\033[92m{prefix}\033[0m {msg}")


def log_info(msg: str, indent: int = 0):
    prefix = "  " * indent + "•"
    print(f"{prefix} {msg}")


def log_warn(msg: str, indent: int = 0):
    prefix = "  " * indent + "⚠"
    print(f"\033[93m{prefix}\033[0m {msg}")


def log_err(msg: str, indent: int = 0):
    prefix = "  " * indent + "✗"
    print(f"\033[91m{prefix}\033[0m {msg}", file=sys.stderr)


def sanitize_folder_name(name: str) -> str:
    forbidden = '/\\:*?"<>|'
    for ch in forbidden:
        name = name.replace(ch, "_")
    return name.strip()


def get_mod_name_from_filelist(folder_path: str) -> str | None:
    fl_path = os.path.join(folder_path, "filelist.xml")
    if not os.path.isfile(fl_path):
        return None
    try:
        root = ET.parse(fl_path).getroot()
        return root.get("name")
    except Exception as e:
        log_warn(f"Failed to parse filelist.xml: {e}", indent=2)
        return None


def copy_mod(src: str, dst: str) -> bool:
    if os.path.exists(dst):
        log_info(f"Removing existing folder: {dst}", indent=2)
        shutil.rmtree(dst)
    log_info(f"Copying: {src} → {dst}", indent=2)
    shutil.copytree(src, dst, symlinks=True)
    return True


def main():
    print()
    print("╔══════════════════════════════════════════╗")
    print("║      Prepare Local Mods from SERVER      ║")
    print("╚══════════════════════════════════════════╝")
    print()

    if not os.path.isfile(MODLIST_PATH):
        log_err(f"Mod list not found: {MODLIST_PATH}")
        sys.exit(1)

    log_info(f"Reading mod list: {MODLIST_PATH}")
    try:
        tree = ET.parse(MODLIST_PATH)
        root = tree.getroot()
    except Exception as e:
        log_err(f"Failed to parse mod list: {e}")
        sys.exit(1)

    mods = root.findall("Workshop")
    if not mods:
        log_warn("No <Workshop> entries found in mod list")
        sys.exit(0)

    log_info(f"Found {len(mods)} workshop mod(s)")
    print()

    copied = 0
    skipped = 0
    errors = 0

    for mod in mods:
        mod_id = mod.get("id", "").strip()
        mod_name = mod.get("name", "").strip()

        if not mod_id:
            log_warn(f"Skipping entry with no id: name='{mod_name}'", indent=1)
            skipped += 1
            continue

        print(f"[{mod_id}] {mod_name}")
        log_info(f"Processing mod: {mod_name}", indent=1)

        src_dir = os.path.join(WORKSHOP_DIR, mod_id)
        if not os.path.isdir(src_dir):
            log_err(f"Workshop folder not found: {src_dir}", indent=2)
            errors += 1
            continue

        display_name = get_mod_name_from_filelist(src_dir)
        if not display_name:
            log_warn("No name found in filelist.xml, using Steam name", indent=2)
            display_name = mod_name

        safe_name = sanitize_folder_name(display_name)
        if not safe_name:
            log_warn("Sanitized name is empty, using mod ID as fallback", indent=2)
            safe_name = mod_id

        dst_dir = os.path.join(LOCALMODS_DIR, safe_name)

        try:
            copy_mod(src_dir, dst_dir)
            log_ok(f"Copied as: {safe_name}", indent=2)
            copied += 1
        except Exception as e:
            log_err(f"Copy failed: {e}", indent=2)
            errors += 1

        print()

    print("─" * 50)
    log_ok(f"Copied: {copied}")
    log_info(f"Skipped: {skipped}")
    if errors:
        log_err(f"Errors: {errors}")

    local_mods = root.findall("Local")
    if local_mods:
        print()
        log_info(f"Checking {len(local_mods)} local mod reference(s)…")
        for lm in local_mods:
            lm_name = lm.get("name", "").strip()
            if not lm_name:
                continue
            lm_path = os.path.join(LOCALMODS_DIR, sanitize_folder_name(lm_name))
            if os.path.isdir(lm_path):
                log_ok(f"Local mod present: {lm_name}", indent=1)
            else:
                log_warn(f"Local mod NOT found: {lm_name}", indent=1)
        print()

    if not errors and skipped == 0:
        print()
        log_ok("All mods prepared successfully!")
    print()


if __name__ == "__main__":
    main()
