//! Surface traits the proc macros implement.

use crate::ir::{AffectTarget, NamedType, Transport};
use crate::runtime::{MizanError, RequestHandle};
use serde_json::Value;
use std::future::Future;
use std::pin::Pin;

/// A type that participates in the Mizan IR. Generated by `#[derive(Mizan)]`.
///
/// `TYPE_NAME` is a `const` (not a function) so it's usable in `static`
/// initializers — TypeEntry's `name` field reads it directly without an
/// init-time function call.
pub trait MizanType {
    const TYPE_NAME: &'static str;
    fn shape() -> NamedType;

    fn type_name() -> &'static str {
        Self::TYPE_NAME
    }
}

/// A marker type for a Mizan context. Generated by `#[mizan::context]`.
pub trait ContextMarker {
    const NAME: &'static str;
}

/// One Mizan-registered function. Generated by `#[mizan(...)]` on async fns.
///
/// Everything here is plain data except `dispatch`, which is the type-erased
/// runtime entry point used by the HTTP adapter.
pub trait FunctionSpec: Send + Sync {
    fn name(&self) -> &'static str;
    fn camel_name(&self) -> &'static str;
    fn has_input(&self) -> bool;
    fn input_type(&self) -> Option<&'static str>;
    fn output_type(&self) -> &'static str;
    fn output_nullable(&self) -> bool {
        false
    }
    fn context(&self) -> Option<&'static str> {
        None
    }
    fn affects(&self) -> &'static [AffectTarget] {
        &[]
    }
    fn merge(&self) -> &'static [&'static str] {
        &[]
    }
    fn transport(&self) -> Transport {
        Transport::Http
    }
    fn private(&self) -> bool {
        false
    }
    fn is_form(&self) -> bool {
        false
    }
    fn form_name(&self) -> Option<&'static str> {
        None
    }
    fn form_role(&self) -> Option<&'static str> {
        None
    }

    /// Field-shape description of this function's Input parameters, used by
    /// the context builder to compute shared-param elevation. Empty when
    /// `has_input()` is false.
    fn input_params(&self) -> &'static [InputParam] {
        &[]
    }

    /// Type-erased dispatch. The HTTP adapter calls this with deserialized
    /// JSON arguments; the macro-generated impl deserializes into the
    /// function's typed input, awaits the body, and serializes the result.
    fn dispatch<'a>(
        &'a self,
        req: RequestHandle<'a>,
        args: Value,
    ) -> Pin<Box<dyn Future<Output = Result<Value, MizanError>> + Send + 'a>>;
}

/// One parameter of a function's synthesized Input. The macro emits a static
/// slice of these so the context builder can find shared params across
/// context members and produce the `context { param ... shared-by ... }`
/// section of the IR.
#[derive(Debug, Clone, Copy)]
pub struct InputParam {
    pub name: &'static str,
    pub primitive: crate::ir::Primitive,
    pub required: bool,
}
