from datetime import datetime
from pathlib import Path
import platform
import os
from typing import Union
import json
import toml
import typer
import logging
import sys
import string
import subprocess

from mulch.constants import FALLBACK_SCAFFOLD


logger = logging.getLogger(__name__)


def calculate_nowtime_foldername() -> str:
    now = datetime.now()
    # use an Obsidian-template-friendly hyphen between the month number and the month name.
    return now.strftime("%Y_%m-%B_%d")

def resolve_first_existing_path(bases: list[Path], filenames: list[str]) -> Path | None:
    for base in bases:
        for name in filenames:
            candidate = base / name
            if candidate.exists():
                return candidate
    return None
    
def resolve_scaffold(order_of_respect: list[Path], filenames_of_respect: list[str]) -> dict:
    for base_path in order_of_respect:
        logger.info(f"base_path = {base_path}")
        logger.info(f"type(base_path) = {type(base_path)}")
        if not isinstance(base_path, Path):
            continue

        for filename in filenames_of_respect:
            candidate = Path(base_path) / filename
            if candidate.exists():
                try:
                    if candidate.suffix == ".toml":
                        typer.secho(f"📄 Loading scaffold from: {candidate}", fg=typer.colors.CYAN)
                        return toml.load(candidate)
                    elif candidate.suffix == ".json":
                        typer.secho(f"📄 Loading scaffold from: {candidate}", fg=typer.colors.CYAN)
                        with candidate.open("r", encoding="utf-8") as f:
                            return json.load(f)
                except Exception as e:
                    typer.secho(f"⚠️ Error loading scaffold from {candidate}: {e}", fg=typer.colors.RED)
                    logger.warning(f"Failed to load scaffold: {candidate}, error: {e}")
                    continue

    typer.secho("📦 Falling back to embedded scaffold structure.", fg=typer.colors.YELLOW)
    return FALLBACK_SCAFFOLD

def index_to_letters(index: int) -> str:
    """Converts a 1-based index to a sequence of lowercase letters"""
    letters = string.ascii_lowercase
    result = ""
    while index > 0:
        index, remainder = divmod(index - 1,26)
        result = letters[remainder] + result
    return result

def get_local_appdata_path(appname=None) -> Path:
    if platform.system() == "Windows":
        # Local app data, e.g., C:\Users\User\AppData\Local
        return Path(os.getenv("LOCALAPPDATA", Path.home() / "AppData" / "Local")) / appname
    else:
        # On Linux/macOS fallback to the same as get_global_config_path
        return get_global_config_path(appname)


def get_global_config_path(appname=None) -> Path:
    if platform.system() == "Windows":
        return Path(os.getenv("APPDATA", Path.home())) / appname
    else:
        return Path(os.getenv("XDG_CONFIG_HOME", Path.home() / ".config")) / appname
    
def get_user_root(appname=None) -> Path:
    """
    Return the user's home config path for mulch, e.g.:
    - Windows: %USERPROFILE%
    - Linux/macOS: ~/.config
    """
    if platform.system() == "Windows":
        return Path(os.environ.get("USERPROFILE", Path.home())) / appname
    else:
        # Unix-like systems
        return Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / appname
    

def get_username_from_home_directory():
    home_dir = Path.home()  # Get the home directory
    return home_dir.name    # Extract the username from the home directory path

#VALID_EXTENSIONS = [".toml", ".json"]

def try_load_scaffold_file(path: Path) -> dict | None:
    try:
        if not path.exists():
            return None

        with open(path, "r", encoding="utf-8") as f:
            content = f.read().strip()
            if not content:
                logger.warning(f"{path} is empty. Continuing to next scaffold source.")
                return None

            if path.suffix == ".json":
                return json.loads(content)
            elif path.suffix == ".toml":
                return toml.loads(content)
            else:
                logger.warning(f"Unsupported scaffold file type: {path}")
    except Exception as e:
        logger.warning(f"Failed to load scaffold from {path}: {e}")
    return None
def open_editor(file_path: Path):
    """Open the file in an appropriate system editor."""
    if sys.platform.startswith("win"):
        os.startfile(str(file_path))
    elif sys.platform == "darwin":
        subprocess.run(["open", str(file_path)])
    else:
        # For Linux: prefer $EDITOR, fallback to nano
        editor = os.getenv("EDITOR", "nano")
        subprocess.run([editor, str(file_path)])

def get_default_untitled_workspace_name_based_on_operating_system(workspaces_dir,override_os=None):
    os_name = platform.system()
    if override_os is not None:
        os_name = override_os
    if os_name == "Windows": 
        base_name = "New workspace"
        n = 1
        while True:
            suffix = f" ({n})" if n > 1 else ""
            folder_name = f"{base_name}{suffix}"
            if not (workspaces_dir / folder_name).exists(): # 
                return folder_name
            n+=1
    elif os_name == "Darwin":
        base_name = "untitled workspace"
        n = 1
        while True:
            suffix = f" {n}" if n > 1 else ""
            folder_name = f"{base_name}{suffix}"
            if not (workspaces_dir / folder_name).exists(): # 
                return folder_name
            n+=1
    elif os_name == "Linux":
        base_name = "New Workspace"
        n = 0
        while True:
            suffix = f" ({n})" if n > 0 else ""
            folder_name = f"{base_name}{suffix}"
            if not (workspaces_dir / folder_name).exists(): # 
                return folder_name
            n+=1
    else:
        return get_default_untitled_workspace_name_based_on_operating_system(workspaces_dir,override_os="Linux")

    
    
def dedupe_paths(paths):
    seen = set()
    unique = []
    for p in paths:
        resolved = str(p.resolve()) if p.exists() else str(p)
        if resolved not in seen:
            unique.append(p)
            seen.add(resolved)
    return unique
