//! The MCP server handler: five thin tool entry points over
//! [`crate::tools`], plus the server identity and instructions.

use rmcp::{
    ErrorData, ServerHandler,
    handler::server::{router::tool::ToolRouter, wrapper::Parameters},
    model::{CallToolResult, Content, Implementation, ServerCapabilities, ServerInfo},
    tool, tool_handler, tool_router,
};

use crate::tools::area_brief::{self, AreaBriefParams};
use crate::tools::navdata;
use crate::tools::resolve::{self, ResolveParams};
use crate::tools::route_brief::{self, RouteBriefParams};

/// Guidance handed to connecting MCP clients with the server identity.
const INSTRUCTIONS: &str = "Aeronautical context for AI agents: FAA NASR-derived identifier \
resolution and live aviationweather.gov (AWC) weather, plus Leidos Flight Service when vendor \
credentials are configured.\n\
\n\
Live tools: resolve (identifier to kind/coordinates/name), area_brief (METAR/TAF/PIREP/SIGMET \
around an airport), navdata_sync (bring the local FAA NASR snapshot store current), \
navdata_status (store and subscription health), route_brief (brief a Garmin .fpl flight plan along its corridor). On a new machine run navdata_sync once before \
resolve or area_brief.\n\
\n\
Planned capabilities, documented but not yet callable: ownship_status and submit_command, \
mirroring aerocontext-core's OwnshipStatusProvider and ControlCommandProvider capability \
traits; they become tools when a provider implementation lands.\n\
\n\
All data is advisory — never use it as a sole source for real-world navigation or flight \
decisions. When quoting weather, cite each product's raw_text verbatim.";

/// Stateless MCP server over the aerocontext system.
#[derive(Clone)]
pub struct AeroContextServer {
    tool_router: ToolRouter<Self>,
}

impl Default for AeroContextServer {
    fn default() -> Self {
        Self::new()
    }
}

#[tool_router]
impl AeroContextServer {
    /// A server exposing the live aerocontext tool set.
    pub fn new() -> Self {
        Self {
            tool_router: Self::tool_router(),
        }
    }

    #[tool(
        description = "Resolve an aeronautical identifier (ICAO/FAA airport, navaid, or published fix) to its kind, WGS84 coordinates, and name using the device's current FAA NASR navdata snapshot."
    )]
    async fn resolve(
        &self,
        Parameters(params): Parameters<ResolveParams>,
    ) -> Result<CallToolResult, ErrorData> {
        let snapshot = crate::store::load_current_snapshot().await?;
        let report = resolve::resolve_in_snapshot(&snapshot, &params.ident)?;
        Ok(CallToolResult::success(vec![Content::json(&report)?]))
    }

    #[tool(
        description = "Live weather products (METAR by default; optionally TAF/PIREP/SIGMET) within a radius of an airport, gathered per source with attribution. Quote raw_text verbatim."
    )]
    async fn area_brief(
        &self,
        Parameters(params): Parameters<AreaBriefParams>,
    ) -> Result<CallToolResult, ErrorData> {
        let request = area_brief::validate(params)?;
        let report = area_brief::run(&request).await?;
        Ok(CallToolResult::success(vec![Content::json(&report)?]))
    }

    #[tool(
        description = "Brief a flight route from a Garmin .fpl flight plan: paste the .fpl document as `fpl`. Composes per-corridor AWC requests and a Leidos route briefing, returning weather products, each source's full narrative (NOTAMs/TFRs/adverse conditions), and — with an aircraft `profile` — a vertical cross-section with time en route and fuel. Quote raw_text and narratives verbatim; all data is advisory."
    )]
    async fn route_brief(
        &self,
        Parameters(params): Parameters<RouteBriefParams>,
    ) -> Result<CallToolResult, ErrorData> {
        let report = route_brief::run(params).await?;
        Ok(CallToolResult::success(vec![Content::json(&report)?]))
    }

    #[tool(
        description = "Download or refresh the device's FAA NASR navdata snapshots from its subscriptions; run this once before resolve/area_brief on a new machine."
    )]
    async fn navdata_sync(&self) -> Result<CallToolResult, ErrorData> {
        let report = navdata::sync_store().await?;
        Ok(CallToolResult::success(vec![Content::text(report)]))
    }

    #[tool(
        description = "Show the navdata subscriptions, store contents, and publication-cycle tracking at a glance."
    )]
    async fn navdata_status(&self) -> Result<CallToolResult, ErrorData> {
        let report = navdata::store_status().await?;
        Ok(CallToolResult::success(vec![Content::text(report)]))
    }
}

#[tool_handler(router = self.tool_router)]
impl ServerHandler for AeroContextServer {
    fn get_info(&self) -> ServerInfo {
        ServerInfo::new(ServerCapabilities::builder().enable_tools().build())
            .with_server_info(Implementation::new(
                "aerocontext",
                env!("CARGO_PKG_VERSION"),
            ))
            .with_instructions(INSTRUCTIONS)
    }
}

#[cfg(test)]
mod tests;
