from pathlib import Path

from fastapi import APIRouter, HTTPException, Request, status
from pydantic import BaseModel

from mosaygent.command_runner import run_command
from mosaygent.logger import get_logger
from mosaygent.services.environment import EnvironmentService
from mosaygent.services.expo import ExpoService
from mosaygent.services.github import GitHubService

logger = get_logger(__name__)

github_service = GitHubService()

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


def get_environment_service(request: Request) -> EnvironmentService:
    """Get the Environment service from app state."""
    if not hasattr(request.app.state, 'environment_service'):
        logger.info("Initializing environment service")
        request.app.state.environment_service = EnvironmentService()
    return request.app.state.environment_service


class SetDirectoryRequest(BaseModel):
    path: str


class UpdatePackageRequest(BaseModel):
    version: str
    working_directory: str


@router.post("/environment/set-directory", status_code=status.HTTP_200_OK)
async def set_directory(request: Request, body: SetDirectoryRequest) -> dict:
    """Set the project directory and initialize Expo service if available."""
    service = get_environment_service(request)

    try:
        service.set_project_dir(body.path)

        expo_dir = service._find_react_native_codebase()
        if expo_dir:
            logger.info(f"Initializing Expo service for directory: {expo_dir}")

            if hasattr(request.app.state, 'expo_service'):
                old_service = request.app.state.expo_service
                if old_service.process and old_service.process.poll() is None:
                    logger.info("Stopping existing Expo service")
                    old_service.stop()

            request.app.state.expo_service = ExpoService(app_dir=expo_dir)
            logger.info("Expo service initialized successfully")
        else:
            logger.info("No React Native directory found in project")

        return {"success": True, "path": body.path}
    except FileNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except NotADirectoryError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.exception(f"Failed to set directory: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to set directory: {str(e)}")


@router.get("/environment/status", status_code=status.HTTP_200_OK)
async def get_status(request: Request) -> dict:
    """Get comprehensive status of both codebases."""
    service = get_environment_service(request)

    api_status = service.check_codebase_status("api")
    mobile_status = service.check_codebase_status("mobile")

    return {
        "project_dir": service.get_project_dir(),
        "api": api_status,
        "mobile": mobile_status,
    }


@router.post("/environment/clone-api", status_code=status.HTTP_200_OK)
async def clone_api(request: Request) -> dict:
    """Initialize API project from the python-api template."""
    service = get_environment_service(request)
    project_dir = service.get_project_dir()

    if not project_dir:
        raise HTTPException(status_code=400, detail="Project directory not set")

    try:
        return await github_service.init_api_from_template(Path(project_dir))
    except FileExistsError as e:
        raise HTTPException(status_code=409, detail=str(e))
    except Exception as e:
        logger.exception(f"Failed to initialize API project: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/environment/update-mosaygent", status_code=status.HTTP_200_OK)
async def update_mosaygent(body: UpdatePackageRequest) -> dict:
    """Update the mosaygent package to a specific version in a target directory."""
    logger.info(f"Updating mosaygent to version {body.version} in {body.working_directory}")

    work_dir = Path(body.working_directory).resolve()
    if not work_dir.exists():
        raise HTTPException(status_code=404, detail=f"Directory not found: {work_dir}")
    if not work_dir.is_dir():
        raise HTTPException(status_code=400, detail=f"Path is not a directory: {work_dir}")

    try:
        result = await run_command(
            ["uv", "add", "--group", "dev", f"mosaygent=={body.version}"],
            cwd=str(work_dir),
            timeout=120,
        )
        logger.info(f"Package update completed: {result.output}")

        return {
            "message": f"mosaygent updated to {body.version}. Please restart the server for changes to take effect.",
            "output": result.output,
        }
    except Exception as e:
        logger.exception(f"Failed to update mosaygent: {e}")
        raise HTTPException(status_code=500, detail=str(e))
