import re

from fastapi import APIRouter, HTTPException, Request, status

from mosaygent.command_runner import run_command
from mosaygent.logger import get_logger
from mosaygent.services.expo import ExpoService

logger = get_logger(__name__)

router = APIRouter(
    tags=['Expo Routes'],
)


def get_expo_service(request: Request) -> ExpoService:
    """Get the Expo service from app state."""
    if not hasattr(request.app.state, 'expo_service'):
        logger.error("Expo service not initialized - project directory may not be set")
        raise HTTPException(
            status_code=400,
            detail="Expo service not initialized. Please set the project directory first using /environment/set-directory"
        )
    return request.app.state.expo_service


@router.get("/expo-version")
async def expo_version() -> dict:
    """Get locally installed Expo CLI version information."""
    logger.info("Fetching Expo version")

    result = await run_command(['npx', 'expo', '--version'], timeout=30)
    logger.debug(f"Expo command output: {result.stdout[:100]}")

    path_result = await run_command(['which', 'npx'], timeout=5)
    npx_path = path_result.stdout.strip()
    logger.debug(f"NPX installation path: {npx_path}")

    version_match = re.search(r'(\d+\.\d+\.\d+)', result.stdout)
    if version_match:
        version = version_match.group(1)
        logger.info(f"Successfully parsed Expo version: {version}")
        return {
            "version": version,
            "npx_path": npx_path,
            "full_output": result.stdout.strip()
        }

    logger.error(f"Failed to parse Expo version from output: {result.stdout}")
    raise HTTPException(
        status_code=500,
        detail="Could not parse Expo version from output"
    )


@router.get("/expo-auth")
async def check_expo_auth() -> dict:
    """Check EAS CLI installation and auth status."""
    logger.info("Checking EAS CLI installation and auth status")

    # Check if EAS CLI is installed
    eas_result = await run_command(["eas", "--version"], timeout=10, raise_on_error=False)

    if not eas_result.success:
        logger.warning("EAS CLI is not installed")
        return {
            "installed": False,
            "logged_in": False,
            "install_command": "npm install -g eas-cli",
            "login_command": "eas login",
        }

    version_match = re.search(r'(\d+\.\d+\.\d+)', eas_result.stdout)
    version = version_match.group(1) if version_match else eas_result.stdout.strip()
    logger.info(f"EAS CLI is installed: {version}")

    # Check auth status
    whoami_result = await run_command(["eas", "whoami"], timeout=10, raise_on_error=False)

    if whoami_result.success and whoami_result.stdout.strip():
        username = whoami_result.stdout.strip()
        logger.info(f"User is logged in to Expo as: {username}")
        return {
            "installed": True,
            "version": version,
            "logged_in": True,
            "username": username,
        }

    logger.info("User is not logged in to Expo")
    return {
        "installed": True,
        "version": version,
        "logged_in": False,
        "login_command": "eas login",
    }


@router.post("/expo/start", status_code=status.HTTP_200_OK)
async def start_expo_server(request: Request) -> dict:
    """Start the Expo development server."""
    logger.info("Starting Expo development server")
    service = get_expo_service(request)

    try:
        result = service.start()
        await service.wait_for_ready()
        return result
    except FileNotFoundError as e:
        logger.error(f"App directory not found: {e}")
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.exception(f"Failed to start Expo server: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to start Expo: {e}")


@router.post("/expo/stop", status_code=status.HTTP_200_OK)
async def stop_expo_server(request: Request) -> dict:
    """Stop the Expo development server."""
    logger.info("Stopping Expo development server")
    service = get_expo_service(request)

    try:
        return service.stop()
    except Exception as e:
        logger.exception(f"Failed to stop Expo server: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to stop Expo: {e}")


@router.get("/expo/status", status_code=status.HTTP_200_OK)
async def get_expo_status(request: Request) -> dict:
    """Get the status of the Expo development server."""
    logger.info("Getting Expo development server status")
    service = get_expo_service(request)
    return service.get_status()


@router.post("/expo/reload", status_code=status.HTTP_200_OK)
async def trigger_reload(request: Request) -> dict:
    """Trigger a reload on the Expo development server."""
    logger.info("Triggering reload")
    service = get_expo_service(request)
    success = service.trigger_reload()
    if success:
        return {"message": "Reload triggered"}
    else:
        return {"message": "Reload failed - no source files found to touch"}


@router.get("/expo/logs")
async def get_expo_logs(request: Request) -> dict:
    """Get Expo output logs."""
    logger.info("Fetching Expo logs")
    service = get_expo_service(request)
    logs = service.get_logs()
    return {
        "logs": logs,
        "count": len(logs)
    }


@router.get("/expo/connection", status_code=status.HTTP_200_OK)
async def get_expo_connection(request: Request) -> dict:
    """Get Metro connection information including URL and port."""
    logger.info("Getting Expo connection info")
    service = get_expo_service(request)
    return service.get_connection_info()
