/// The resource component mirroring fastmcp/resources/base.py and
/// fastmcp/resources/types.py.
///
/// Python's concrete subclasses (TextResource, BinaryResource, FileResource,
/// HttpResource, DirectoryResource) map to factory functions supplying a
/// read closure. File-, HTTP- and directory-backed resources need native
/// IO and are deferred to the transport layer.

///|
/// A registered resource.
pub(all) struct Resource {
  component : @component.ComponentBase
  uri : String
  mime_type : String
  annotations : @types.Annotations?
  read_fn : async () -> RawResourceValue raise @exceptions.FastMCPError
}

///|
pub impl @component.Component for Resource with fn base(self) {
  self.component
}

///|
pub impl @component.Component for Resource with fn identifier(self) {
  self.uri
}

///|
pub impl @component.Component for Resource with fn key(self) {
  let base_key = @component.ComponentBase::make_key(
    self.component.key_prefix,
    self.uri,
  )
  "\{base_key}@\{self.component.version.unwrap_or("")}"
}

///|
pub impl @component.Component for Resource with fn get_meta(self) {
  self.component.get_meta()
}

///|
/// Register a resource at `uri`. The name defaults to the URI when absent.
pub fn Resource::new(
  uri : String,
  read_fn~ : async () -> RawResourceValue raise @exceptions.FastMCPError,
  name? : String,
  version? : String,
  title? : String,
  description? : String,
  icons? : Array[@types.Icon],
  mime_type~ : String = "text/plain",
  tags~ : @set.Set[String] = @set.Set::from_array([]),
  meta? : Map[String, Json],
  annotations? : @types.Annotations,
) -> Resource {
  {
    component: @component.ComponentBase::new(
      "resource",
      name.unwrap_or(uri),
      version?,
      title?,
      description?,
      icons?,
      tags~,
      meta?,
    ),
    uri,
    mime_type,
    annotations,
    read_fn,
  }
}

///|
/// A resource backed by inline text.
pub fn Resource::text(
  uri : String,
  text~ : String,
  name? : String,
  version? : String,
  title? : String,
  description? : String,
  icons? : Array[@types.Icon],
  mime_type~ : String = "text/plain",
  tags~ : @set.Set[String] = @set.Set::from_array([]),
  meta? : Map[String, Json],
  annotations? : @types.Annotations,
) -> Resource {
  Resource::new(
    uri,
    read_fn=() => Text(text),
    name?,
    version?,
    title?,
    description?,
    icons?,
    mime_type~,
    tags~,
    meta?,
    annotations?,
  )
}

///|
/// A resource backed by inline bytes.
pub fn Resource::binary(
  uri : String,
  data~ : Bytes,
  name? : String,
  version? : String,
  title? : String,
  description? : String,
  icons? : Array[@types.Icon],
  mime_type~ : String = "application/octet-stream",
  tags~ : @set.Set[String] = @set.Set::from_array([]),
  meta? : Map[String, Json],
  annotations? : @types.Annotations,
) -> Resource {
  Resource::new(
    uri,
    read_fn=() => Blob(data),
    name?,
    version?,
    title?,
    description?,
    icons?,
    mime_type~,
    tags~,
    meta?,
    annotations?,
  )
}

///|
/// A resource backed by a closure computing its value on read.
pub fn Resource::from_function(
  uri : String,
  read_fn~ : async () -> RawResourceValue raise @exceptions.FastMCPError,
  name? : String,
  version? : String,
  title? : String,
  description? : String,
  icons? : Array[@types.Icon],
  mime_type~ : String = "text/plain",
  tags~ : @set.Set[String] = @set.Set::from_array([]),
  meta? : Map[String, Json],
  annotations? : @types.Annotations,
) -> Resource {
  Resource::new(
    uri,
    read_fn~,
    name?,
    version?,
    title?,
    description?,
    icons?,
    mime_type~,
    tags~,
    meta?,
    annotations?,
  )
}

///|
/// Read the resource content.
pub async fn Resource::read(
  self : Resource,
) -> RawResourceValue raise @exceptions.FastMCPError {
  (self.read_fn)()
}

///|
/// Convert a raw result to a `ResourceResult`, forwarding this resource's
/// declared MIME type and component metadata to each content item.
pub fn Resource::convert_result(
  self : Resource,
  raw_value : RawResourceValue,
) -> ResourceResult {
  convert_raw_to_resource_result(
    raw_value,
    mime_type=self.mime_type,
    meta?=self.component.meta,
  )
}

///|
/// Server entry point for resource reads.
pub async fn Resource::read_result(
  self : Resource,
) -> ResourceResult raise @exceptions.FastMCPError {
  self.convert_result(self.read())
}

///|
/// Convert the resource to its wire representation.
pub fn Resource::to_mcp_resource(self : Resource) -> @types.Resource {
  {
    uri: self.uri,
    name: self.component.name,
    title: self.component.title,
    description: self.component.description,
    mime_type: Some(self.mime_type),
    size: None,
    annotations: self.annotations,
    meta: Some(Resource::get_meta(self)),
  }
}

///|
pub extend Resource with @component.Component::{base, identifier, key, get_meta}