"""Dismiss Fusion 360 recovery dialogs — macOS.

After a crash or force-kill, Fusion shows two types of recovery dialogs:

1. "Recovered Documents" list dialog (window titled "Fusion360"):
   Shows all recovery files with Open/Delete/Close buttons.
   Dismissed via the AX close button (mac_ui.close_window_bg).

2. "Open recovery document instead?" prompt:
   Appears when opening a file that has a recovery document.
   Has Yes/No buttons. We press Tab + Enter to choose No, skipping
   recovery and opening the cloud version instead.

Recovery files are NOT deleted — they are moved to ~/.adom/recovery/fusion/
so the user can manually recover them if needed. Each batch is timestamped.
"""

import os
import shutil
import time

from handlers import mac_ui as _mac


def _get_fusion_crash_recovery_dirs() -> list:
    """Find all CrashRecovery directories under Fusion's app-support data.

    Fusion stores recovery files at:
      ~/Library/Application Support/Autodesk/Autodesk Fusion (360)/<USER_ID>/CrashRecovery/

    There may be multiple user ID folders. Returns list of existing
    CrashRecovery dirs that contain at least one file.
    """
    bases = [
        os.path.expanduser("~/Library/Application Support/Autodesk/Autodesk Fusion 360"),
        os.path.expanduser("~/Library/Application Support/Autodesk/Autodesk Fusion"),
    ]

    dirs = []
    for base in bases:
        if not os.path.isdir(base):
            continue
        for entry in os.listdir(base):
            cr_dir = os.path.join(base, entry, "CrashRecovery")
            if os.path.isdir(cr_dir) and os.listdir(cr_dir):
                dirs.append(cr_dir)
    return dirs


def relocate_recovery_files() -> dict:
    """Move Fusion crash recovery files to ~/.adom/recovery/fusion/.

    Instead of deleting recovery files (which removes a useful safety net),
    we relocate them to Adom's own recovery folder. Each batch gets a
    timestamped subfolder so the user can find and restore them if needed.

    Returns dict with:
      - moved: number of files/folders moved
      - dest: destination directory (or None if nothing moved)
      - sources: list of source CrashRecovery dirs that were processed
    """
    cr_dirs = _get_fusion_crash_recovery_dirs()
    if not cr_dirs:
        return {"moved": 0, "dest": None, "sources": []}

    # Create timestamped destination
    timestamp = time.strftime("%Y%m%d_%H%M%S")
    adom_home = os.path.join(os.path.expanduser("~"), ".adom")
    dest_base = os.path.join(adom_home, "recovery", "fusion", timestamp)
    os.makedirs(dest_base, exist_ok=True)

    moved = 0
    sources = []
    for cr_dir in cr_dirs:
        sources.append(cr_dir)
        for item in os.listdir(cr_dir):
            src = os.path.join(cr_dir, item)
            dst = os.path.join(dest_base, item)
            # Handle name collisions by appending a suffix
            if os.path.exists(dst):
                base_name, ext = os.path.splitext(item)
                dst = os.path.join(dest_base, f"{base_name}_{moved}{ext}")
            try:
                shutil.move(src, dst)
                moved += 1
            except Exception:
                # If move fails (file locked), try copy-then-delete
                try:
                    if os.path.isdir(src):
                        shutil.copytree(src, dst)
                    else:
                        shutil.copy2(src, dst)
                    shutil.rmtree(src) if os.path.isdir(src) else os.remove(src)
                    moved += 1
                except Exception:
                    pass  # File may be locked by Fusion — skip it

    # Clean up empty CrashRecovery dirs
    for cr_dir in cr_dirs:
        try:
            if os.path.isdir(cr_dir) and not os.listdir(cr_dir):
                os.rmdir(cr_dir)
        except Exception:
            pass

    # If nothing was actually moved, remove the empty timestamp dir
    if moved == 0:
        try:
            os.rmdir(dest_base)
        except Exception:
            pass
        return {"moved": 0, "dest": None, "sources": sources}

    return {"moved": moved, "dest": dest_base, "sources": sources}


def _find_window_by_title(title_substring: str) -> int:
    """CGWindowID of the first visible window whose title contains the substring, or 0."""
    found = _mac.find_windows_by_title(title_substring)
    return found[0][0] if found else 0


def _find_fusion_dialog_windows() -> list:
    """Fusion-owned non-main windows titled like the recovery list dialog."""
    return [d["hwnd"] for d in _mac.find_dialog_windows()
            if (d.get("title") or "").strip().lower()
            in ("fusion360", "fusion", "autodesk fusion")]


def _send_key(winid: int, key: str, pause: float = 0.05):
    """Send a named key to a window. CGEvent keys land in the FOCUSED app
    (there is no post-to-window on mac), so raise the target window first to
    avoid typing into whatever the user has focused."""
    if winid:
        _mac.raise_window(winid)
        time.sleep(0.1)
    _mac.send_named_key(key)
    time.sleep(pause)


def _dismiss_recovery_prompt(winid: int) -> bool:
    """Dismiss an 'Open recovery document instead?' dialog by choosing No.

    The dialog has Yes (focused by default) and No buttons. Tab moves focus
    to No, Enter clicks it — skipping recovery and opening the cloud version."""
    _mac.raise_window(winid)
    time.sleep(0.2)
    _send_key(winid, "tab")
    time.sleep(0.2)
    _send_key(winid, "enter")
    return True


def dismiss_recovery_dialog(max_wait: float = 5.0) -> bool:
    """Find and dismiss all Fusion 360 recovery dialogs.

    Before dismissing, relocates recovery files from Fusion's CrashRecovery
    directory to ~/.adom/recovery/fusion/<timestamp>/ so the user can
    manually recover them if needed.

    Handles the dialog types in priority order:
    1. "Open recovery document instead?" — dismissed via Tab+Enter (No)
    2. "Fusion360" titled dialog — the Recovered Documents list, closed in background
    3. A window explicitly titled "Recovered Documents" — closed in background
    4. Fallback: Send Escape to the Fusion main window

    Loops to handle multiple recovery prompts (one per recovered file).
    Returns True if any dismiss attempt was made.
    """
    # Relocate recovery files BEFORE dismissing dialogs
    # This preserves them in ~/.adom/recovery/fusion/ for the user
    try:
        reloc = relocate_recovery_files()
        if reloc["moved"] > 0:
            import logging
            logging.getLogger(__name__).info(
                "Relocated %d recovery file(s) to %s",
                reloc["moved"], reloc["dest"]
            )
    except Exception:
        pass  # Don't let relocation failure block dialog dismissal

    deadline = time.monotonic() + max_wait
    dismissed_any = False

    while time.monotonic() < deadline:
        # Priority 1: "Open recovery document instead?" prompt
        prompt_id = _find_window_by_title("Open recovery document instead?")
        if prompt_id:
            _dismiss_recovery_prompt(prompt_id)
            dismissed_any = True
            time.sleep(0.5)
            continue  # Check for more prompts

        # Priority 2: "Fusion360" titled dialogs (Recovered Documents list)
        dialog_ids = _find_fusion_dialog_windows()
        if dialog_ids:
            for winid in dialog_ids:
                _mac.close_window_bg(winid)
            dismissed_any = True
            time.sleep(0.5)
            continue  # Check for more

        # Priority 3: A window explicitly titled "Recovered Documents"
        winid = _find_window_by_title("Recovered Documents")
        if winid:
            _mac.close_window_bg(winid)
            dismissed_any = True
            time.sleep(0.5)
            continue

        # If we already dismissed something, check one more time
        if dismissed_any:
            time.sleep(0.5)
            # One final check
            if not _find_window_by_title("Open recovery document instead?") \
               and not _find_fusion_dialog_windows() \
               and not _find_window_by_title("Recovered Documents"):
                break
            continue

        # Priority 4: Send Escape to the main Fusion window (last resort)
        fusion_id = _find_window_by_title("Autodesk Fusion")
        if fusion_id:
            _send_key(fusion_id, "escape")
            dismissed_any = True
            time.sleep(1.0)
            continue

        time.sleep(0.5)

    return dismissed_any
