#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# =============================================================================
#  Pre‑run Setup Guide (everything you need before executing this script)
# =============================================================================
#
# 1️⃣  Python version
#     • Requires Python 3.6+. Verify with:  python3 --version
#
# 2️⃣  Install the Internet Archive CLI client
#     • Provides the `ia` executable used for downloading.
#       pip install --upgrade internetarchive
#       or enter: apt-get install internetarchive
#
# 3️⃣  Ensure `ia` is on your PATH
#     • Test with:  ia --version
#
# 4️⃣  (Optional) Authenticate with your Internet Archive account
#     • Run once:  ia configure
#
# 5️⃣  Permissions for the destination folder
#     • The script will create the folder you specify if it does not exist.
#
# 6️⃣  Save this file (e.g. download_any_type.py) and make it executable:
#       chmod +x download_any_type.py
#
# 7️⃣  Run the script:
#       ./download_any_type.py   or   python3 download_any_type.py
#
# -------------------------------------------------------------------------
# After completing the steps above you are ready to use the script.
# -------------------------------------------------------------------------

import os
import shutil
import subprocess
import sys
from pathlib import Path


# ----------------------------------------------------------------------
# Helper: build the unchanged ia command, injecting the user‑provided glob
# ----------------------------------------------------------------------
def build_command(collection: str, file_glob: str) -> list[str]:
    """
    Return the exact `ia` command we want to run.
    The only variable part is the glob pattern supplied by the user.
    """
    return [
        "ia",
        "download",
        "-g",
        file_glob,                   # e.g. *.pdf, *.zip, *.*, etc.
        "--search",
        f"collection:{collection}",
    ]


# ----------------------------------------------------------------------
# Helper: pretty‑print the command for the user
# ----------------------------------------------------------------------
def pretty_print_cmd(cmd: list[str]) -> None:
    print("\n🛠️  Executing:", " ".join(cmd))


# ----------------------------------------------------------------------
# Helper: move all matched files to the target folder (flattened)
# ----------------------------------------------------------------------
def move_downloaded_files(target_dir: Path, extensions: tuple[str, ...]) -> None:
    """
    Recursively find files whose suffix matches one of `extensions`
    and move them into `target_dir`, flattening the hierarchy.
    """
    start_dir = Path.cwd()

    for root, _, files in os.walk(start_dir):
        for fname in files:
            # Skip files that don't match the requested extensions
            if extensions and not fname.lower().endswith(extensions):
                continue

            src_path = Path(root) / fname

            # Skip files already inside the target folder
            if src_path.parent.resolve() == target_dir.resolve():
                continue

            dest_path = target_dir / fname

            # Resolve name collisions
            counter = 1
            while dest_path.exists():
                stem = dest_path.stem
                suffix = dest_path.suffix
                dest_path = target_dir / f"{stem}_{counter}{suffix}"
                counter += 1

            # Ensure target exists (safe guard)
            target_dir.mkdir(parents=True, exist_ok=True)

            shutil.move(str(src_path), str(dest_path))
            print(f"Moved: {src_path} → {dest_path}")


# ----------------------------------------------------------------------
# Helper: delete empty sub‑directories (preserving the target folder)
# ----------------------------------------------------------------------
def delete_empty_subdirs(root: Path, preserve: Path) -> None:
    """Walk bottom‑up and remove any empty directory except `preserve`."""
    for dirpath, _, _ in os.walk(root, topdown=False):
        cur = Path(dirpath)

        # Never delete the destination folder itself
        if cur.resolve() == preserve.resolve():
            continue

        # If the directory is empty, remove it
        if not any(cur.iterdir()):
            try:
                cur.rmdir()
                print(f"Deleted empty directory: {cur}")
            except OSError as exc:
                print(f"⚠️  Could not delete {cur}: {exc}", file=sys.stderr)


# ----------------------------------------------------------------------
# Helper: prompt for a destination folder, creating it if needed
# ----------------------------------------------------------------------
def prompt_destination_folder(prompt_msg: str) -> Path:
    """
    Ask the user for a folder path.
    * If it exists and is a directory → use it.
    * If it does not exist → create it (including parents).
    * If it exists but is not a directory → ask again.
    """
    while True:
        user_input = input(prompt_msg).strip()
        if not user_input:
            print("❌ You must enter a path.", file=sys.stderr)
            continue

        candidate = Path(user_input).expanduser().resolve()

        if candidate.exists():
            if candidate.is_dir():
                return candidate
            else:
                print(
                    f"❌ The path '{candidate}' exists but is not a directory. Please try again.",
                    file=sys.stderr,
                )
                continue
        else:
            try:
                candidate.mkdir(parents=True, exist_ok=True)
                print(f"Created destination folder: {candidate}")
                return candidate
            except OSError as exc:
                print(f"❌ Could not create directory '{candidate}': {exc}", file=sys.stderr)
                continue


# ----------------------------------------------------------------------
# Helper: prompt for a glob pattern (file type) and validate it
# ----------------------------------------------------------------------
def prompt_file_glob() -> str:
    """
    Ask the user which file type(s) to download.
    The user should provide a glob pattern such as:
        *.pdf   – only PDFs
        *.zip   – only ZIP archives
        *.*     – any file with an extension
        *       – literally everything (including files without an extension)
    The function ensures the pattern contains at least one '*'.
    """
    while True:
        pattern = input(
            "Enter the file‑type pattern to download (e.g., *.pdf, *.zip, *.* for any file): "
        ).strip()
        if not pattern:
            print("❌ Pattern cannot be empty.", file=sys.stderr)
            continue
        if "*" not in pattern:
            print("❌ A glob pattern must contain '*'. Try again.", file=sys.stderr)
            continue
        return pattern


# ----------------------------------------------------------------------
# Helper: derive a tuple of extensions from the glob for post‑move filtering
# ----------------------------------------------------------------------
def extensions_from_glob(glob_pattern: str) -> tuple[str, ...]:
    """
    Convert a simple glob like '*.pdf' or '*.*' into a tuple of lower‑case suffixes.
    For patterns that match everything (e.g., '*', '*.*'), return an empty tuple
    meaning “accept any file”.
    """
    # Strip leading '*.' if present
    if glob_pattern.startswith("*."):
        ext = glob_pattern[2:].lower()
        return (f".{ext}",)
    # '*.*' means any extension
    if glob_pattern == "*.*":
        return ()
    # '*' means any file, regardless of extension
    if glob_pattern == "*":
        return ()
    # For more complex patterns we fall back to “accept any”
    return ()


# ----------------------------------------------------------------------
# Main driver
# ----------------------------------------------------------------------
def main() -> None:
    # --------------------------------------------------------------
    # Banner – each piece on its own line
    # --------------------------------------------------------------
    print("PHAT‑INTERNET-ARCHIVER‑DOWNLOADER, v1.0: 2026")
    print("Licensed under the GNU GPL Version 2.0:")
    print("https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt")
    print("Coded by cr1mson (lead developer) cr1mson@phatstar.org")
    print("Coded by warmfuzzy (editor) society@phatstar.org")
    print("Coded by SilentPartner (magic) phatstarsociety@proton.me")
    print("Archived on PHATstar.net and BBSDay.org")
    print("-" * 80)

    # 1️⃣ Collection name
    collection = input(
        "Enter the collection name (e.g. amigashopper): "
    ).strip()
    if not collection:
        print("❌ Collection name cannot be empty.", file=sys.stderr)
        sys.exit(1)

    # 2️⃣ File‑type pattern (glob) to download
    file_glob = prompt_file_glob()
    # Derive extensions for the move‑step filtering (empty tuple = accept all)
    allowed_exts = extensions_from_glob(file_glob)

    # 3️⃣ Destination folder (create if missing)
    target_dir = prompt_destination_folder(
        "Enter the folder where you want ALL downloaded files moved to: "
    )

    # 4️⃣ Build and run the unchanged ia command (with user‑provided glob)
    cmd = build_command(collection, file_glob)
    pretty_print_cmd(cmd)

    try:
        subprocess.run(cmd, check=True)
        print("\n✅ ia download completed.")
    except subprocess.CalledProcessError as exc:
        print(
            f"\n❌ The `ia` command failed with exit code {exc.returncode}.",
            file=sys.stderr,
        )
        sys.exit(exc.returncode)
    except FileNotFoundError:
        print(
            "\n❌ The `ia` executable was not found. Install it with:\n    pip install internetarchive",
            file=sys.stderr,
        )
        sys.exit(1)

    # 5️⃣ Move the downloaded files (filtered by extension if applicable)
    print("\n🚚 Moving downloaded files to the target folder...")
    move_downloaded_files(target_dir, allowed_exts)

    # 6️⃣ Clean up empty sub‑directories left behind
    print("\n🧹 Cleaning up empty sub‑directories...")
    delete_empty_subdirs(Path.cwd(), preserve=target_dir)

    print("\n🎉 All done! Files are now in:", target_dir)


if __name__ == "__main__":
    main()
