// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains export wrappers for the {{.Capability.Interface}} capability.
// It is intended for use in Navidrome plugins built with extism-pdk.
{{if or .Capability.Structs .Capability.SharedAliases}}
use serde::{Deserialize, Serialize};
{{- if hasHashMap .Capability}}
use std::collections::HashMap;
{{- end}}
{{- if .Capability.HasByteFields}}{{template "base64_bytes_module" .}}{{- end}}

// Helper functions for skip_serializing_if with numeric types
#[allow(dead_code)]
fn is_zero_i32(value: &i32) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_u32(value: &u32) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_i64(value: &i64) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_u64(value: &u64) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_f32(value: &f32) -> bool { *value == 0.0 }
#[allow(dead_code)]
fn is_zero_f64(value: &f64) -> bool { *value == 0.0 }
{{- end}}

{{- /* Generate deprecated aliases to the shared types crate */ -}}
{{- range .Capability.SharedAliases}}

#[deprecated(note = "use {{rustSharedNote .Target}}")]
pub type {{.Name}} = {{rustSharedTarget .Target}};
{{- end}}

{{- /* Generate type alias definitions */ -}}
{{- range .Capability.TypeAliases}}

{{- if .Doc}}
{{rustDocComment .Doc}}
{{- end}}
pub type {{.Name}} = {{rustTypeAlias .Type}};
{{- end}}

{{- /* Generate const definitions */ -}}
{{- range .Capability.Consts}}
{{- if .Values}}
{{- $type := .Type}}
{{- range $i, $v := .Values}}

{{- if $v.Doc}}
{{rustDocComment $v.Doc}}
{{- end}}
{{- /* Use the type alias name if a named type is provided, otherwise use &'static str */ -}}
{{- if $type}}
pub const {{rustConstName $v.Name}}: {{$type}} = {{$v.Value}};
{{- else}}
pub const {{rustConstName $v.Name}}: &'static str = {{$v.Value}};
{{- end}}
{{- end}}
{{- end}}
{{- end}}

{{- /* Generate struct definitions */ -}}
{{- range .Capability.Structs}}

{{- if .Doc}}
{{rustDocComment .Doc}}
{{- else}}
/// {{.Name}} represents the {{.Name}} data structure.
{{- end}}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct {{.Name}} {
{{- range .Fields}}
{{- if .Doc}}
{{rustDocComment .Doc | indent 4}}
{{- end}}
{{- if .OmitEmpty}}
    #[serde(default, skip_serializing_if = "{{skipSerializingFunc .Type}}")]
{{- else}}
    #[serde(default)]
{{- end}}
{{- if .IsByteSlice}}
    #[serde(with = "base64_bytes")]
{{- end}}
    pub {{rustFieldName .Name}}: {{fieldRustType .}},
{{- end}}
}
{{- end}}

/// Error represents an error from a capability method.
#[derive(Debug)]
pub struct Error {
    pub message: String,
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.message)
    }
}

impl std::error::Error for Error {}

impl Error {
    pub fn new(message: impl Into<String>) -> Self {
        Self { message: message.into() }
    }
}

{{- /* Generate main interface based on required flag */ -}}
{{if .Capability.Required}}

/// {{agentName .Capability}} requires all methods to be implemented.
{{- if .Capability.Doc}}
{{rustDocComment .Capability.Doc}}
{{- end}}
pub trait {{agentName .Capability}} {
{{- range .Capability.Methods}}
    /// {{.Name}}{{if .Doc}} - {{.Doc}}{{end}}
    {{- if and .HasInput .HasOutput}}
    fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<{{rustOutputType .Output.Type}}, Error>;
    {{- else if .HasInput}}
    fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<(), Error>;
    {{- else if .HasOutput}}
    fn {{rustMethodName .Name}}(&self) -> Result<{{rustOutputType .Output.Type}}, Error>;
    {{- else}}
    fn {{rustMethodName .Name}}(&self) -> Result<(), Error>;
    {{- end}}
{{- end}}
}

/// Register all exports for the {{agentName .Capability}} capability.
/// This macro generates the WASM export functions for all trait methods.
#[macro_export]
macro_rules! register_{{snakeCase .Package}} {
    ($plugin_type:ty) => {
        {{- range .Capability.Methods}}
        #[extism_pdk::plugin_fn]
        pub fn {{.ExportName}}(
            {{- if .HasInput}}
            req: extism_pdk::Json<{{rustMethodType .Input.Type}}>
            {{- end}}
        ) -> extism_pdk::FnResult<{{if .HasOutput}}extism_pdk::Json<{{rustMethodType .Output.Type}}>{{else}}(){{end}}> {
            let plugin = <$plugin_type>::default();
            {{- if and .HasInput .HasOutput}}
            let result = $crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
            Ok(extism_pdk::Json(result))
            {{- else if .HasInput}}
            $crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
            Ok(())
            {{- else if .HasOutput}}
            let result = $crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin)?;
            Ok(extism_pdk::Json(result))
            {{- else}}
            $crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin)?;
            Ok(())
            {{- end}}
        }
        {{- end}}
    };
}
{{- else}}

{{- /* Generate optional provider interfaces for non-required capabilities */ -}}
{{- range .Capability.Methods}}

/// {{providerInterface .}} provides the {{.Name}} function.
pub trait {{providerInterface .}} {
    {{- if and .HasInput .HasOutput}}
    fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<{{rustOutputType .Output.Type}}, Error>;
    {{- else if .HasInput}}
    fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<(), Error>;
    {{- else if .HasOutput}}
    fn {{rustMethodName .Name}}(&self) -> Result<{{rustOutputType .Output.Type}}, Error>;
    {{- else}}
    fn {{rustMethodName .Name}}(&self) -> Result<(), Error>;
    {{- end}}
}

/// Register the {{rustMethodName .Name}} export.
/// This macro generates the WASM export function for this method.
#[macro_export]
macro_rules! {{registerMacroName .Name}} {
    ($plugin_type:ty) => {
        #[extism_pdk::plugin_fn]
        pub fn {{.ExportName}}(
            {{- if .HasInput}}
            req: extism_pdk::Json<{{rustMethodType .Input.Type}}>
            {{- end}}
        ) -> extism_pdk::FnResult<{{if .HasOutput}}extism_pdk::Json<{{rustMethodType .Output.Type}}>{{else}}(){{end}}> {
            let plugin = <$plugin_type>::default();
            {{- if and .HasInput .HasOutput}}
            let result = $crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
            Ok(extism_pdk::Json(result))
            {{- else if .HasInput}}
            $crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
            Ok(())
            {{- else if .HasOutput}}
            let result = $crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin)?;
            Ok(extism_pdk::Json(result))
            {{- else}}
            $crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin)?;
            Ok(())
            {{- end}}
        }
    };
}
{{- end}}
{{- end}}
