import os
import logging
import subprocess

logger = logging.getLogger('gaze')

# Path to the MCP docker-compose projects, relative to the main app file.
MCP_TOOLS_DIR         = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'tools')
MCP_COMPOSE_DIR       = os.path.join(MCP_TOOLS_DIR, 'danbooru-mcp')
MCP_REPO_URL          = 'https://git.liveaodh.com/aodhan/danbooru-mcp'
CHAR_MCP_COMPOSE_DIR  = os.path.join(MCP_TOOLS_DIR, 'character-mcp')
CHAR_MCP_REPO_URL     = 'https://git.liveaodh.com/aodhan/character-mcp.git'


def _ensure_repo(compose_dir, repo_url, name):
    """Clone or update an MCP source repository inside tools/.

    - If the directory does not exist, clone from repo_url.
    - If it already exists, run ``git pull`` to fetch the latest changes.
    Errors are non-fatal.
    """
    os.makedirs(MCP_TOOLS_DIR, exist_ok=True)
    try:
        if not os.path.isdir(compose_dir):
            logger.info('Cloning %s from %s …', name, repo_url)
            subprocess.run(
                ['git', 'clone', repo_url, compose_dir],
                timeout=120, check=True,
            )
            logger.info('%s cloned successfully.', name)
        else:
            logger.info('Updating %s via git pull …', name)
            subprocess.run(
                ['git', 'pull'],
                cwd=compose_dir,
                timeout=60, check=True,
            )
            logger.info('%s updated.', name)
    except FileNotFoundError:
        logger.warning('git not found on PATH — %s repo will not be cloned/updated.', name)
    except subprocess.CalledProcessError as e:
        logger.warning('git operation failed for %s: %s', name, e)
    except subprocess.TimeoutExpired:
        logger.warning('git timed out while cloning/updating %s.', name)
    except Exception as e:
        logger.warning('Could not clone/update %s repo: %s', name, e)


def _ensure_server_running(compose_dir, repo_url, container_name, name):
    """Ensure an MCP repo is present/up-to-date, then start the Docker
    container if it is not already running.

    Uses ``docker compose up -d`` so the image is built automatically on first
    run.  Errors are non-fatal — the app will still start even if Docker is
    unavailable.

    Skipped when ``SKIP_MCP_AUTOSTART=true`` (set by docker-compose, where the
    MCP service is managed by compose instead).
    """
    if os.environ.get('SKIP_MCP_AUTOSTART', '').lower() == 'true':
        logger.info('SKIP_MCP_AUTOSTART set — skipping %s auto-start.', name)
        return
    _ensure_repo(compose_dir, repo_url, name)
    try:
        result = subprocess.run(
            ['docker', 'ps', '--filter', f'name={container_name}', '--format', '{{.Names}}'],
            capture_output=True, text=True, timeout=10,
        )
        if container_name in result.stdout:
            logger.info('%s container already running.', name)
            return
        logger.info('Starting %s container via docker compose …', name)
        subprocess.run(
            ['docker', 'compose', 'up', '-d'],
            cwd=compose_dir,
            timeout=120,
        )
        logger.info('%s container started.', name)
    except FileNotFoundError:
        logger.warning('docker not found on PATH — %s will not be started automatically.', name)
    except subprocess.TimeoutExpired:
        logger.warning('docker timed out while starting %s.', name)
    except Exception as e:
        logger.warning('Could not ensure %s is running: %s', name, e)


def ensure_mcp_server_running():
    """Ensure the danbooru-mcp Docker container is running."""
    _ensure_server_running(MCP_COMPOSE_DIR, MCP_REPO_URL, 'danbooru-mcp', 'danbooru-mcp')


def ensure_character_mcp_server_running():
    """Ensure the character-mcp Docker container is running."""
    _ensure_server_running(CHAR_MCP_COMPOSE_DIR, CHAR_MCP_REPO_URL, 'character-mcp', 'character-mcp')
