from typing import List, Dict, Any

from cmdlet._shared import Cmdlet, CmdletArg
from SYS.config import load_config, save_config

CMDLET = Cmdlet(
    name=".config",
    summary="Manage configuration settings",
    usage=".config [key] [value]",
    arg=[
        CmdletArg(
            name="key",
            description="Configuration key to update (dot-separated)",
            required=False
        ),
        CmdletArg(
            name="value",
            description="New value for the configuration key",
            required=False
        ),
    ],
)


def flatten_config(config: Dict[str,
                                Any],
                   parent_key: str = "",
                   sep: str = ".") -> List[Dict[str,
                                                Any]]:
    items = []
    for k, v in config.items():
        if k.startswith("_"):  # Skip internal keys
            continue

        new_key = f"{parent_key}{sep}{k}" if parent_key else k
        if isinstance(v, dict):
            items.extend(flatten_config(v, new_key, sep=sep))
        else:
            items.append(
                {
                    "Key": new_key,
                    "Value": str(v),
                    "Type": type(v).__name__,
                    "_selection_args": [new_key],
                }
            )
    return items


def set_nested_config(config: Dict[str, Any], key: str, value: str) -> bool:
    keys = key.split(".")
    d = config

    # Navigate to the parent dict
    for k in keys[:-1]:
        if k not in d or not isinstance(d[k], dict):
            d[k] = {}
        d = d[k]

    last_key = keys[-1]

    # Try to preserve type if key exists
    if last_key in d:
        current_val = d[last_key]
        if isinstance(current_val, bool):
            if value.lower() in ("true", "yes", "1", "on"):
                d[last_key] = True
            elif value.lower() in ("false", "no", "0", "off"):
                d[last_key] = False
            else:
                # Fallback to boolean conversion of string (usually True for non-empty)
                # But for config, explicit is better.
                print(f"Warning: Could not convert '{value}' to boolean. Using string.")
                d[last_key] = value
        elif isinstance(current_val, int):
            try:
                d[last_key] = int(value)
            except ValueError:
                print(f"Warning: Could not convert '{value}' to int. Using string.")
                d[last_key] = value
        elif isinstance(current_val, float):
            try:
                d[last_key] = float(value)
            except ValueError:
                print(f"Warning: Could not convert '{value}' to float. Using string.")
                d[last_key] = value
        else:
            d[last_key] = value
    else:
        # New key, try to infer type
        if value.lower() in ("true", "false"):
            d[last_key] = value.lower() == "true"
        elif value.isdigit():
            d[last_key] = int(value)
        else:
            d[last_key] = value

    return True


def _run(piped_result: Any, args: List[str], config: Dict[str, Any]) -> int:
    # Reload config to ensure we have the latest on disk
    # We don't use the passed 'config' because we want to edit the file
    # and 'config' might contain runtime objects (like worker manager)
    # But load_config() returns a fresh dict from disk (or cache)
    # We should use load_config()

    current_config = load_config()

    # Parse args
    # We handle args manually because of the potential for spaces in values
    # and the @ expansion logic in CLI.py passing args

    if not args:
        # List mode
        items = flatten_config(current_config)
        # Sort by key
        items.sort(key=lambda x: x["Key"])

        # Emit items for ResultTable
        from SYS import pipeline as ctx

        for item in items:
            ctx.emit(item)
        return 0

    # Update mode
    key = args[0]

    if len(args) < 2:
        print(f"Error: Value required for key '{key}'")
        return 1

    value = " ".join(args[1:])

    # Remove quotes if present
    if (value.startswith('"') and value.endswith('"')) or (value.startswith("'")
                                                           and value.endswith("'")):
        value = value[1:-1]

    try:
        set_nested_config(current_config, key, value)
        save_config(current_config)
        print(f"Updated '{key}' to '{value}'")
        return 0
    except Exception as e:
        print(f"Error updating config: {e}")
        return 1


CMDLET.exec = _run
