"""Registry resolution and install path helpers for CLI commands."""

import os
from pathlib import Path
from typing import List, Optional

from armorer.catalog import resolve_playbook
from armorer.registry import AppMetadata, AppRegistry

from armorer.apps.influencerpy import registry_runtime as influencerpy_registry_runtime
from armorer.apps.openclaw import registry_runtime as openclaw_registry_runtime
from armorer.cli.common import console


def resolve_install_path(path: str, to_host: bool = False) -> Path:
    """
    Translate paths between host and container.
    If to_host=True: Translates /app/installed/x -> /host/path/installed/x
    If to_host=False: Translates /host/path/installed/x -> /app/installed/x
    """
    p = Path(path)
    if not os.path.exists('/.dockerenv'):
        raw = str(p)
        if raw.startswith('/app/installed/'):
            tail = raw.split('/app/installed/', 1)[1]
            candidates = [
                Path.cwd() / 'installed' / tail,
                Path.home() / 'workplace' / 'SecureNeural' / 'Armorer' / 'installed' / tail,
            ]
            for cand in candidates:
                if cand.exists():
                    return cand
        return p

    host_root = os.getenv('HOST_PROJECT_ROOT')

    if to_host:
        if str(p).startswith('/app'):
            if host_root:
                rel = p.relative_to('/app')
                return Path(host_root) / rel
            if 'installed/' in str(p):
                parts = str(p).split('installed/', 1)
                return Path('installed') / parts[1]
    else:
        if host_root and str(p).startswith(host_root):
            return p
        if 'installed/' in str(p):
            parts = str(p).split('installed/', 1)
            return Path('/app/installed') / parts[1]

    return p


def try_persist_registry_app_metadata(
    registry: AppRegistry,
    app_meta: AppMetadata,
    *,
    context: str,
    warn: bool = True,
) -> bool:
    try:
        registry.add_app(app_meta)
        return True
    except OSError as exc:
        if warn:
            console.print(f'[dim]Skipping registry metadata update during {context}: {exc}[/dim]')
        return False


def infer_agent_id(raw: str) -> str:
    text = (raw or '').strip()
    spec = resolve_playbook(text)
    if spec and getattr(spec, 'id', None):
        return str(spec.id).strip().lower()
    if text.startswith('http://') or text.startswith('https://'):
        name = text.rstrip('/').split('/')[-1]
        if name.endswith('.git'):
            name = name[:-4]
        return name.lower()
    return text.lower()


def list_apps_with_openclaw_fallback(registry: AppRegistry) -> List[AppMetadata]:
    openclaw_registry_runtime.list_apps_with_openclaw_fallback(
        registry,
        infer_agent_id=infer_agent_id,
        resolve_install_path=resolve_install_path,
        persist_registry_app_metadata=try_persist_registry_app_metadata,
    )
    return influencerpy_registry_runtime.list_apps_with_influencerpy_fallback(
        registry,
        infer_agent_id=infer_agent_id,
        resolve_install_path=resolve_install_path,
        persist_registry_app_metadata=try_persist_registry_app_metadata,
    )


def instances_for_agent(registry: AppRegistry, agent_key: str) -> List[AppMetadata]:
    needle = infer_agent_id(agent_key)
    apps = list_apps_with_openclaw_fallback(registry) if needle in {'openclaw', 'influencerpy'} else registry.list_apps()
    out: List[AppMetadata] = []
    for app in apps:
        app_id = (app.agent_id or app.name or '').lower()
        if app_id == needle:
            out.append(app)
    return out


def get_app_with_openclaw_fallback(registry: AppRegistry, name: str) -> Optional[AppMetadata]:
    requested = infer_agent_id(name)
    if requested == 'openclaw':
        return openclaw_registry_runtime.get_app_with_openclaw_fallback(
            registry,
            name,
            infer_agent_id=infer_agent_id,
            resolve_install_path=resolve_install_path,
            persist_registry_app_metadata=try_persist_registry_app_metadata,
        )
    if requested == 'influencerpy':
        return influencerpy_registry_runtime.get_app_with_influencerpy_fallback(
            registry,
            name,
            infer_agent_id=infer_agent_id,
            resolve_install_path=resolve_install_path,
            persist_registry_app_metadata=try_persist_registry_app_metadata,
        )
    return registry.get_app(name)


def print_agent_not_found(agent: str) -> None:
    console.print(
        f"[red]Error: Agent '{agent}' not found.[/red]  Run [bold]armorer list[/bold] to see installed agents."
    )
    agent_id = infer_agent_id(agent)
    if agent_id == 'openclaw':
        console.print(
            '[dim]OpenClaw is not installed for this environment. Ask Armorer chat/TUI to `install openclaw`, or run `armorer install openclaw --yes`.[/dim]'
        )
    elif agent_id == 'influencerpy':
        console.print(
            '[dim]InfluencerPy is not installed for this environment. Run `armorer install influencerpy --yes` to provision the managed web stack.[/dim]'
        )


def can_reinstall_stale_default_openclaw_alias(
    registry: AppRegistry,
    agent: str,
    instance_name: str,
) -> bool:
    agent_id = infer_agent_id(agent)
    if agent_id == 'openclaw':
        return openclaw_registry_runtime.can_reinstall_stale_default_openclaw_alias(
            registry,
            agent,
            instance_name,
            infer_agent_id=infer_agent_id,
            resolve_install_path=resolve_install_path,
            persist_registry_app_metadata=try_persist_registry_app_metadata,
        )
    if agent_id == 'influencerpy':
        return influencerpy_registry_runtime.can_reinstall_stale_default_influencerpy_alias(
            registry,
            agent,
            instance_name,
            infer_agent_id=infer_agent_id,
            resolve_install_path=resolve_install_path,
            persist_registry_app_metadata=try_persist_registry_app_metadata,
        )
    return False


def next_instance_alias(registry: AppRegistry, agent_id: str) -> str:
    """Generate next unique alias for an agent family."""
    style = (os.getenv('ARMORER_ALIAS_STYLE') or 'base').strip().lower()
    existing_names = {app.name for app in registry.list_apps()}
    family = instances_for_agent(registry, agent_id)
    n = max(2, len(family) + 1)
    while True:
        candidate = f'agent_{n}' if style == 'generic' else f'{agent_id}_{n}'
        if candidate not in existing_names:
            return candidate
        n += 1
