"""Functions for rclone and local filesystem interaction."""

import os
import subprocess
from typing import List, Optional, Tuple


def run_command(command: List[str], timeout: int = 10) -> Tuple[int, str]:
    """Execute a command and return (returncode, output)."""
    try:
        result = subprocess.run(
            command,
            capture_output=True,
            text=True,
            timeout=timeout,
            check=False,
        )
        return result.returncode, result.stdout + result.stderr
    except subprocess.TimeoutExpired:
        return 1, "Command timed out"
    except Exception as e:
        return 1, str(e)


def list_remotes() -> List[str]:
    """Get list of rclone remotes."""
    rc, output = run_command(["rclone", "listremotes"])
    if rc != 0:
        return []
    return [line.strip() for line in output.splitlines() if line.strip()]


def list_remote_dir(remote: str, path: str = "") -> List[str]:
    """List directories and files in a remote path."""
    # The user specifically mentioned lsd, so let's ensure we get directories
    full_remote_path = f"{remote}{path}"

    # Try using lsf as primary because it's much easier to parse and handles both
    # But we'll fallback to lsd for directories as suggested if lsf seems empty/failed
    rc, output = run_command(
        ["rclone", "lsf", "--dir-slash", "--format", "p", full_remote_path]
    )

    if rc == 0 and output.strip():
        items = [line.strip() for line in output.splitlines() if line.strip()]
        dirs = sorted([i for i in items if i.endswith("/")])
        files = sorted([i for i in items if not i.endswith("/")])
        return dirs + files

    # Fallback/Supplemental: Use lsd as specifically suggested
    rc_lsd, output_lsd = run_command(["rclone", "lsd", full_remote_path])
    if rc_lsd == 0:
        dirs = []
        for line in output_lsd.splitlines():
            if line.strip():
                # lsd output looks like: "          -1 2023-10-10 10:10:10         -1 My Directory"
                # We need to correctly capture the name after the first 4 columns
                parts = line.split(None, 4)
                if len(parts) >= 5:
                    dirs.append(parts[4].strip() + "/")
        return sorted(dirs)

    return []


def list_local_dir(path: str) -> List[str]:
    """List directories and files in a local path."""
    try:
        items = os.listdir(path)
        # Add trailing slash to directories
        formatted_items = []
        for item in items:
            if os.path.isdir(os.path.join(path, item)):
                formatted_items.append(item + "/")
            else:
                formatted_items.append(item)

        # Sort: directories first, then files
        dirs = sorted([i for i in formatted_items if i.endswith("/")])
        files = sorted([i for i in formatted_items if not i.endswith("/")])
        return dirs + files
    except Exception:
        return []


def run_rclone_copy(mode: int, src: str, dst: str, dry_run: bool = False):
    """Run rclone copy command based on mode.

    Modes:
    1: Single file (copyto)
    2: Directory traversed (copy)
    3: Directory no-traverse (copy --no-traverse)
    """
    import sys
    import subprocess
    import os

    # Common exclude patterns - use /** for directories to exclude their contents
    exclude_patterns = [
        "--exclude",
        ".git/**",
        "--exclude",
        ".venv/**",
        "--exclude",
        "venv/**",
        "--exclude",
        "env/**",
        "--exclude",
        ".opencode/**",
        "--exclude",
        ".openai_*",
        "--exclude",
        ".*~",
        "--exclude",
        ".python-version",
        "--exclude",
        ".python-cache/**",
        "--exclude",
        ".pytest_cache/**",
    ]

    if mode == 1:
        # Single file copy - exclude patterns not supported
        cmd = ["rclone", "copyto", src, dst, "--progress"]
    elif mode == 2:
        cmd = ["rclone", "copy", src, dst, "--progress"] + exclude_patterns
    elif mode == 3:
        cmd = [
            "rclone",
            "copy",
            src,
            dst,
            "--progress",
            "--no-traverse",
        ] + exclude_patterns
    else:
        return

    if dry_run:
        cmd.append("--dry-run")

    # Clear screen for a clean output and ensure sane terminal state
    os.system("stty sane && clear")
    print(f"Executing: {' '.join(cmd)}\n")
    if dry_run:
        print("!!! DRY RUN MODE - No files will be copied !!!\n")
    print("-" * 60)

    try:
        # Run and allow user to see output
        result = subprocess.run(cmd, check=False)

        # Call stty sane again after rclone completes
        os.system("stty sane")

        print("-" * 60)
        if result.returncode == 0:
            print(
                "\n\033[92mOperation finished successfully.\033[0m Press Enter to return to mcrc..."
            )
        else:
            print(
                f"\n\033[91mOperation failed (exit code {result.returncode}).\033[0m Press Enter to return to mcrc..."
            )

        # Use a more robust input waiting mechanism
        try:
            sys.stdin.read(1)
        except:
            pass

    except KeyboardInterrupt:
        os.system("stty sane")
        print("\n\n\033[91mOperation cancelled by user.\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass
    except Exception as e:
        os.system("stty sane")
        print(f"\n\n\033[91mError in rclone execution: {e}\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass


def run_rclone_deletefile(remote_path: str):
    """Run rclone deletefile command.

    Args:
        remote_path: The remote path to the file (remote:path/to/file)
    """
    import sys
    import subprocess
    import os

    cmd = ["rclone", "deletefile", remote_path, "--progress"]

    # Clear screen for a clean output and ensure sane terminal state
    os.system("stty sane && clear")
    print(f"Executing: {' '.join(cmd)}\n")
    print("!!! WARNING: REAL DELETE MODE - File will be permanently deleted !!!\n")
    print("-" * 60)

    try:
        # Run and allow user to see output
        result = subprocess.run(cmd, check=False)

        # Call stty sane again after rclone completes
        os.system("stty sane")

        print("-" * 60)
        if result.returncode == 0:
            print(
                "\n\033[92mOperation finished successfully.\033[0m Press Enter to return to mcrc..."
            )
        else:
            print(
                f"\n\033[91mOperation failed (exit code {result.returncode}).\033[0m Press Enter to return to mcrc..."
            )

        # Use a more robust input waiting mechanism
        try:
            sys.stdin.read(1)
        except:
            pass

    except KeyboardInterrupt:
        os.system("stty sane")
        print("\n\n\033[91mOperation cancelled by user.\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass
    except Exception as e:
        os.system("stty sane")
        print(f"\n\n\033[91mError in rclone execution: {e}\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass


def run_rclone_purge(remote_path: str, dry_run: bool = True):
    """Run rclone purge command.

    Args:
        remote_path: The remote path to purge (remote:path/to/dir)
        dry_run: If True, adds --dry-run flag
    """
    import sys
    import subprocess
    import os

    cmd = ["rclone", "purge", remote_path, "--progress"]
    if dry_run:
        cmd.append("--dry-run")

    # Clear screen for a clean output and ensure sane terminal state
    os.system("stty sane && clear")
    print(f"Executing: {' '.join(cmd)}\n")
    if dry_run:
        print("!!! DRY RUN MODE - No files will be deleted !!!\n")
    else:
        print("!!! WARNING: REAL PURGE MODE - Files will be permanently deleted !!!\n")
    print("-" * 60)

    try:
        # Run and allow user to see output
        result = subprocess.run(cmd, check=False)

        # Call stty sane again after rclone completes
        os.system("stty sane")

        print("-" * 60)
        if result.returncode == 0:
            print(
                "\n\033[92mOperation finished successfully.\033[0m Press Enter to return to mcrc..."
            )
        else:
            print(
                f"\n\033[91mOperation failed (exit code {result.returncode}).\033[0m Press Enter to return to mcrc..."
            )

        # Use a more robust input waiting mechanism
        try:
            sys.stdin.read(1)
        except:
            pass

    except KeyboardInterrupt:
        os.system("stty sane")
        print("\n\n\033[91mOperation cancelled by user.\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass
    except Exception as e:
        os.system("stty sane")
        print(f"\n\n\033[91mError in rclone execution: {e}\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass


def run_rclone_sync(src: str, dst: str, dry_run: bool = True):
    """Run rclone sync command.

    Args:
        src: Source path
        dst: Destination path
        dry_run: If True, adds --dry-run flag
    """
    import sys
    import subprocess
    import os

    # Common exclude patterns - use /** for directories to exclude their contents
    exclude_patterns = [
        "--exclude",
        ".git/**",
        "--exclude",
        ".venv/**",
        "--exclude",
        "venv/**",
        "--exclude",
        "env/**",
        "--exclude",
        ".opencode/**",
        "--exclude",
        ".openai_*",
        "--exclude",
        ".*~",
        "--exclude",
        ".python-version",
        "--exclude",
        ".python-cache/**",
        "--exclude",
        ".pytest_cache/**",
    ]

    cmd = ["rclone", "sync", src, dst, "--metadata", "--progress"] + exclude_patterns
    if dry_run:
        cmd.append("--dry-run")

    # Clear screen for a clean output and ensure sane terminal state
    os.system("stty sane && clear")
    print(f"Executing: {' '.join(cmd)}\n")
    if dry_run:
        print("!!! DRY RUN MODE - No files will be deleted or moved !!!\n")
    else:
        print(
            "!!! WARNING: REAL SYNC MODE - Files in destination may be DELETED to match source !!!\n"
        )
    print("-" * 60)

    try:
        # Run and allow user to see output
        result = subprocess.run(cmd, check=False)

        # Call stty sane again after rclone completes
        os.system("stty sane")

        print("-" * 60)
        if result.returncode == 0:
            print(
                "\n\033[92mOperation finished successfully.\033[0m Press Enter to return to mcrc..."
            )
        else:
            print(
                f"\n\033[91mOperation failed (exit code {result.returncode}).\033[0m Press Enter to return to mcrc..."
            )

        # Use a more robust input waiting mechanism
        try:
            sys.stdin.read(1)
        except:
            pass

    except KeyboardInterrupt:
        os.system("stty sane")
        print("\n\n\033[91mOperation cancelled by user.\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass
    except Exception as e:
        os.system("stty sane")
        print(f"\n\n\033[91mError in rclone execution: {e}\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass


def run_rclone_mkdir(remote_path: str):
    """Run rclone mkdir command.

    Args:
        remote_path: The remote path to create (remote:path/to/dir)
    """
    import sys
    import subprocess
    import os

    cmd = ["rclone", "mkdir", remote_path]

    # Clear screen for a clean output and ensure sane terminal state
    os.system("stty sane && clear")
    print(f"Executing: {' '.join(cmd)}\n")
    print("-" * 60)

    try:
        # Run and allow user to see output
        result = subprocess.run(cmd, capture_output=True, text=True, check=False)

        # Call stty sane again after rclone completes
        os.system("stty sane")

        print("-" * 60)
        if result.returncode == 0:
            print(
                "\n\033[92mDirectory created successfully.\033[0m Press Enter to return to mcrc..."
            )
        else:
            print(f"\n\033[91mError: {result.stderr}\033[0m")
            print("\n\033[91mOperation failed.\033[0m Press Enter to return to mcrc...")

        # Use a more robust input waiting mechanism
        try:
            sys.stdin.read(1)
        except:
            pass

    except KeyboardInterrupt:
        os.system("stty sane")
        print("\n\n\033[91mOperation cancelled by user.\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass
    except Exception as e:
        os.system("stty sane")
        print(f"\n\n\033[91mError in rclone execution: {e}\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass


def run_rclone_check(src: str, dst: str):
    """Run rclone check command.

    Args:
        src: Source path
        dst: Destination path
    """
    import sys
    import subprocess
    import os
    import re
    import json
    from datetime import datetime

    # Common exclude patterns - use /** for directories to exclude their contents
    exclude_patterns = [
        "--exclude",
        ".git/**",
        "--exclude",
        ".venv/**",
        "--exclude",
        "venv/**",
        "--exclude",
        "env/**",
        "--exclude",
        ".opencode/**",
        "--exclude",
        ".openai_*",
        "--exclude",
        ".*~",
        "--exclude",
        ".python-version",
        "--exclude",
        ".python-cache/**",
        "--exclude",
        ".pytest_cache/**",
    ]

    cmd = ["rclone", "check", src, dst, "--size-only", "--progress"] + exclude_patterns

    # Clear screen for a clean output and ensure sane terminal state
    os.system("stty sane && clear")
    print(f"Executing: {' '.join(cmd)}\n")
    print("!!! INFO: Check compares files by size only, not content !!!\n")
    print("-" * 60)

    try:
        # Run and capture output while still displaying it
        result = subprocess.run(cmd, capture_output=True, text=True, check=False)

        # Display the output to user
        if result.stdout:
            print(result.stdout)
        if result.stderr:
            print(result.stderr, file=sys.stderr)

        # Call stty sane again after rclone completes
        os.system("stty sane")

        print("-" * 60)
        if result.returncode == 0:
            print(
                "\n\033[92mCheck completed - no differences found.\033[0m Press Enter to return to mcrc..."
            )
            try:
                sys.stdin.read(1)
            except:
                pass
        else:
            print(
                f"\n\033[93mCheck completed with differences (exit code {result.returncode}).\033[0m Press Enter to see details..."
            )
            try:
                sys.stdin.read(1)
            except:
                pass

            # Parse output for files with size differences
            differing_files = []
            output_text = result.stdout + result.stderr

            # Look for lines like: "2026-02-26 09:39:37 ERROR : filename: sizes differ"
            for line in output_text.split("\n"):
                if "ERROR" in line and "sizes differ" in line:
                    # Extract filename - it's between "ERROR : " and ": sizes differ"
                    match = re.search(r"ERROR\s*:\s*(.+?):\s*sizes differ", line)
                    if match:
                        filename = match.group(1).strip()
                        differing_files.append(filename)

            # Remove duplicates while preserving order
            seen = set()
            differing_files = [
                f for f in differing_files if not (f in seen or seen.add(f))
            ]

            if differing_files:
                print("\n\033[93m" + "=" * 80 + "\033[0m")
                print("\033[93mFILES WITH SIZE DIFFERENCES:\033[0m")
                print("\033[93m" + "=" * 80 + "\033[0m\n")

                for filename in differing_files:
                    print(f"\033[96mFile: {filename}\033[0m")
                    print("-" * 80)

                    # Get source file info
                    src_path = f"{src}{filename}"
                    dst_path = f"{dst}{filename}"

                    # Use rclone lsjson to get file info
                    src_info = None
                    dst_info = None

                    try:
                        src_result = subprocess.run(
                            ["rclone", "lsjson", "--stat", src_path],
                            capture_output=True,
                            text=True,
                            timeout=10,
                        )
                        if src_result.returncode == 0:
                            src_info = json.loads(src_result.stdout)
                    except:
                        pass

                    try:
                        dst_result = subprocess.run(
                            ["rclone", "lsjson", "--stat", dst_path],
                            capture_output=True,
                            text=True,
                            timeout=10,
                        )
                        if dst_result.returncode == 0:
                            dst_info = json.loads(dst_result.stdout)
                    except:
                        pass

                    # Display comparison
                    if src_info:
                        size_src = src_info.get("Size", "N/A")
                        if isinstance(size_src, int):
                            size_src = f"{size_src:,} bytes"
                        mtime_src = src_info.get("ModTime", "N/A")
                        if mtime_src and mtime_src != "N/A":
                            try:
                                # Parse ISO format timestamp
                                dt = datetime.fromisoformat(
                                    mtime_src.replace("Z", "+00:00")
                                )
                                mtime_src = dt.strftime("%Y-%m-%d %H:%M:%S")
                            except:
                                pass
                        print(f"  local:  Size: {size_src:<20}  Modified: {mtime_src}")
                    else:
                        print(
                            f"  local:  \033[91mFile not found or inaccessible\033[0m"
                        )

                    if dst_info:
                        size_dst = dst_info.get("Size", "N/A")
                        if isinstance(size_dst, int):
                            size_dst = f"{size_dst:,} bytes"
                        mtime_dst = dst_info.get("ModTime", "N/A")
                        if mtime_dst and mtime_dst != "N/A":
                            try:
                                dt = datetime.fromisoformat(
                                    mtime_dst.replace("Z", "+00:00")
                                )
                                mtime_dst = dt.strftime("%Y-%m-%d %H:%M:%S")
                            except:
                                pass
                        print(f"  remote: Size: {size_dst:<20}  Modified: {mtime_dst}")
                    else:
                        print(
                            f"  remote: \033[91mFile not found or inaccessible\033[0m"
                        )

                    print()

                print("\033[93m" + "=" * 80 + "\033[0m")
                print("Press Enter to return to mcrc...")
                try:
                    sys.stdin.read(1)
                except:
                    pass

    except KeyboardInterrupt:
        os.system("stty sane")
        print("\n\n\033[91mCheck cancelled by user.\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass
    except Exception as e:
        os.system("stty sane")
        print(f"\n\n\033[91mError in rclone execution: {e}\033[0m")
        print("Press Enter to return to mcrc...")
        try:
            sys.stdin.read(1)
        except:
            pass
