use crate::command::CommandBuilder;
use crate::config::Config;
use crate::server::ServerType;
use crate::task::TaskBuilder;
use crate::version::Version;
use async_trait::async_trait;
use std::fmt;
use std::path::PathBuf;

#[async_trait]
pub trait PluginBuilder: Send + Sync + 'static {
	/// 插件名称
	fn name(&self) -> &'static str;
	/// 插件版本
	fn version(&self) -> Version;

	/// api版本
	fn abi_version(&self) -> Version;

	/// 插件描述
	fn description(&self) -> &'static str;
	/// 插件作者
	fn author(&self) -> Option<&'static str>;

	/// 插件命令前缀
	fn prefix(&self) -> Option<&'static str> {
		None
	}

	/// 任务列表
	fn tasks(&self) -> Vec<Box<dyn TaskBuilder>>;

	/// 命令列表
	fn commands(&self) -> Vec<Box<dyn CommandBuilder>>;

	/// 插件配置文件
	fn config(&self) -> Option<Vec<Box<dyn Config>>> {
		None
	}

	/// 路由管理
	fn server(&self) -> Option<ServerType> {
		None
	}
	/// 插件初始化函数
	async fn init(&self) -> Result<(), Box<dyn std::error::Error>>;
}

#[derive(Debug, Clone)]
pub struct Plugin {
	/// 插件名称
	pub name: String,
	/// 插件版本
	pub version: Version,
	/// 插件作者
	pub author: Option<String>,
}

#[derive(Clone)]
pub enum PluginType {
	/// 基于文件路径加载的动态库插件
	Path(PathBuf),
	/// 静态链接的插件
	Builder(&'static dyn PluginBuilder),
}

impl fmt::Debug for PluginType {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		match self {
			PluginType::Path(path) => f.debug_struct("Path").field("path", path).finish(),
			PluginType::Builder(_) => f.debug_struct("Builder").finish(),
		}
	}
}
impl From<PathBuf> for PluginType {
	fn from(path: PathBuf) -> Self {
		PluginType::Path(path)
	}
}

impl From<&'static dyn PluginBuilder> for PluginType {
	fn from(builder: &'static dyn PluginBuilder) -> Self {
		PluginType::Builder(builder)
	}
}

#[derive(Debug, Clone)]
pub enum PluginId {
	Index(u64),
	Name(String),
}
impl From<u64> for PluginId {
	fn from(value: u64) -> Self {
		Self::Index(value)
	}
}
impl From<String> for PluginId {
	fn from(value: String) -> Self {
		Self::Name(value)
	}
}
impl From<&str> for PluginId {
	fn from(value: &str) -> Self {
		Self::Name(value.to_string())
	}
}
