from __future__ import annotations

import argparse
import asyncio
from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI, HTTPException, Request
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse

import api
from task_manager import TaskManager
from push_stream import PushStreamManager
from detection_manager import DetectionManager
from self_updater import SelfUpdater
from updater_server import UpdaterServer
from port_monitor import PortMonitor
from media_manager import MediaManager


def create_app(
    tasks_dir: str | Path,
    host: str,
    port: int,
    state_file: str | Path | None = None,
    apps_dir: str | Path | None = None,
) -> FastAPI:
    # 内部回调地址使用 127.0.0.1（0.0.0.0 不可作为 HTTP 请求的 target）
    internal_host = "127.0.0.1" if host in ("0.0.0.0", "::") else host
    internal_base = f"http://{internal_host}:{port}"
    task_manager = TaskManager(
        tasks_dir=tasks_dir,
        internal_api_base=internal_base,
        state_file=state_file,
        apps_dir=apps_dir,
    )

    @asynccontextmanager
    async def lifespan(app: FastAPI):
        # startup
        await task_manager.start_watchdog(interval=5.0)
        await task_manager.start_system_info_loop(interval=2.0)
        app.state.updater_server.start()
        print(f"Updater upload server started on port 8080")
        app.state.port_monitor.start()
        print(f"Port monitor started (enabled={app.state.port_monitor.enabled}, event-driven)")
        await app.state.push_stream.start_flight_monitor()
        app.state.detection.start_flight_monitor()
        await asyncio.get_event_loop().run_in_executor(None, app.state.detection.start_auto)
        await app.state.push_stream.start_all_auto()
        # 启动媒体管理器
        data_dir = Path(__file__).parent / "data"
        app.state.media_manager = MediaManager(data_dir)
        api._set_media_manager_ref(app.state.media_manager)
        # 程序重启后，默认所有流为停止状态
        app.state.media_manager.reset_all_streams_on_startup()
        # 启动 go2rtc（空配置，不加载任何流）
        try:
            await app.state.media_manager.restart_go2rtc()
            print("Media manager started")
        except Exception as e:
            print(f"Media manager start warning: {e}")
        # 启动媒体自动停止监控
        app.state._media_auto_stop_task = asyncio.create_task(api.media_auto_stop_monitor())
        print("Media auto-stop monitor started")
        print(f"Loaded {len(task_manager.list_definitions())} task definitions")
        for tid, tdef in task_manager.list_definitions().items():
            print(f"  - {tid}: {tdef.name}")
        yield
        # shutdown
        task_manager.stop_watchdog()
        task_manager.stop_system_info_loop()
        await app.state.push_stream.stop_flight_monitor()
        app.state.detection.stop_flight_monitor()
        app.state.detection.stop()
        app.state.updater_server.stop()
        app.state.port_monitor.stop()
        if hasattr(app.state, "_media_auto_stop_task"):
            app.state._media_auto_stop_task.cancel()
        # 停止媒体管理器
        if hasattr(app.state, "media_manager"):
            try:
                await app.state.media_manager.stop_all()
                print("Media manager stopped")
            except Exception:
                pass
        api._set_media_manager_ref(None)

    app = FastAPI(
        title="Drone Task Manager",
        version="1.0.0",
        lifespan=lifespan,
    )

    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    app.state.task_manager = task_manager
    app.state.push_stream = PushStreamManager()
    app.state.detection = DetectionManager()
    app.state.self_updater = SelfUpdater()
    app.state.updater_server = UpdaterServer(port=8080)
    app.state.port_monitor = PortMonitor()

    app.include_router(api.router)
    app.add_websocket_route("/ws", api.websocket_endpoint)

    # 挂载文件根目录为静态文件服务（替代 nginx 目录服务）
    for root_name, root_info in api.FILE_ROOT_DIRS.items():
        root_path = Path(root_info["path"]).expanduser().resolve()
        if root_path.exists() and root_path.is_dir():
            try:
                app.mount(f"/{root_name}", StaticFiles(directory=str(root_path)), name=root_name)
            except Exception as e:
                print(f"Warning: could not mount /{root_name}: {e}")

    # 挂载 /tmp 目录
    tmp_path = Path("/tmp").resolve()
    if tmp_path.exists() and tmp_path.is_dir():
        try:
            app.mount("/tmp", StaticFiles(directory=str(tmp_path)), name="tmp")
        except Exception as e:
            print(f"Warning: could not mount /tmp: {e}")

    # 单文件映射：/uav-480.pcd
    _uav_pcd_path = Path("~/lidar_ws/install/share/px4ctrl/www/uav-480.pcd").expanduser().resolve()
    if _uav_pcd_path.exists():
        @app.get("/uav-480.pcd")
        async def serve_uav_pcd():
            return FileResponse(_uav_pcd_path)

    static_dir = Path(__file__).parent / "static"
    if static_dir.exists():
        app.mount("/static", StaticFiles(directory=static_dir), name="static")

        @app.get("/")
        async def root():
            return FileResponse(static_dir / "index.html")

    return app


# 全局默认 app 实例（用于 uvicorn 直接导入，如 uvicorn main:app）
_app = None

def get_app() -> FastAPI:
    global _app
    if _app is None:
        _app = create_app(
            tasks_dir=str(Path(__file__).parent / "tasks"),
            host="0.0.0.0",
            port=80,
            state_file=str(Path(__file__).parent / "data" / "state.json"),
            apps_dir=str(Path(__file__).parent / "apps"),
        )
    return _app


# uvicorn 导入时直接暴露 app
app = get_app()


def main():
    parser = argparse.ArgumentParser(description="Drone Task Manager")
    parser.add_argument(
        "--tasks-dir",
        type=str,
        default=str(Path(__file__).parent / "tasks"),
        help="任务定义 YAML 目录",
    )
    parser.add_argument("--host", type=str, default="0.0.0.0", help="绑定地址")
    parser.add_argument("--port", type=int, default=80, help="端口")
    parser.add_argument(
        "--state-file",
        type=str,
        default=str(Path(__file__).parent / "data" / "state.json"),
        help="状态持久化文件路径（默认: 安装目录/data/state.json）",
    )
    parser.add_argument(
        "--apps-dir",
        type=str,
        default=str(Path(__file__).parent / "apps"),
        help="App 包安装目录（默认: apps/）",
    )
    args = parser.parse_args()

    app = create_app(
        tasks_dir=args.tasks_dir,
        host=args.host,
        port=args.port,
        state_file=args.state_file,
        apps_dir=args.apps_dir,
    )
    import uvicorn

    uvicorn.run(app, host=args.host, port=args.port, workers=1)


if __name__ == "__main__":
    main()
