import { AuthType, Constants, EToolResources } from 'librechat-data-provider';
import type { TPlugin } from 'librechat-data-provider';
import type { MCPManager } from '~/mcp/MCPManager';
import { LCAvailableTools, LCFunctionTool } from '~/mcp/types';

/**
 * Filters out duplicate plugins from the list of plugins.
 *
 * @param plugins The list of plugins to filter.
 * @returns The list of plugins with duplicates removed.
 */
export const filterUniquePlugins = (plugins?: TPlugin[]): TPlugin[] => {
  const seen = new Set();
  return (
    plugins?.filter((plugin) => {
      const duplicate = seen.has(plugin.pluginKey);
      seen.add(plugin.pluginKey);
      return !duplicate;
    }) || []
  );
};

/**
 * Determines if a plugin is authenticated by checking if all required authentication fields have non-empty values.
 * Supports alternate authentication fields, allowing validation against multiple possible environment variables.
 *
 * @param plugin The plugin object containing the authentication configuration.
 * @returns True if the plugin is authenticated for all required fields, false otherwise.
 */
export const checkPluginAuth = (plugin?: TPlugin): boolean => {
  if (!plugin?.authConfig || plugin.authConfig.length === 0) {
    return false;
  }

  return plugin.authConfig.every((authFieldObj) => {
    const authFieldOptions = authFieldObj.authField.split('||');
    let isFieldAuthenticated = false;

    for (const fieldOption of authFieldOptions) {
      const envValue = process.env[fieldOption];
      if (envValue && envValue.trim() !== '' && envValue !== AuthType.USER_PROVIDED) {
        isFieldAuthenticated = true;
        break;
      }
    }

    return isFieldAuthenticated;
  });
};

/**
 * Converts MCP function format tool to plugin format
 * @param params
 * @param params.toolKey
 * @param params.toolData
 * @param params.customConfig
 * @returns
 */
export function convertMCPToolToPlugin({
  toolKey,
  toolData,
  mcpManager,
}: {
  toolKey: string;
  toolData: LCFunctionTool;
  mcpManager?: MCPManager;
}): TPlugin | undefined {
  if (!toolData.function || !toolKey.includes(Constants.mcp_delimiter)) {
    return;
  }

  const functionData = toolData.function;
  const parts = toolKey.split(Constants.mcp_delimiter);
  const serverName = parts[parts.length - 1];

  const serverConfig = mcpManager?.getRawConfig(serverName);

  const plugin: TPlugin = {
    /** Tool name without server suffix */
    name: parts[0],
    pluginKey: toolKey,
    description: functionData.description || '',
    authenticated: true,
    icon: serverConfig?.iconPath,
  };

  if (!serverConfig?.customUserVars) {
    /** `authConfig` for MCP tools */
    plugin.authConfig = [];
    return plugin;
  }

  const customVarKeys = Object.keys(serverConfig.customUserVars);
  if (customVarKeys.length === 0) {
    plugin.authConfig = [];
  } else {
    plugin.authConfig = Object.entries(serverConfig.customUserVars).map(([key, value]) => ({
      authField: key,
      label: value.title || key,
      description: value.description || '',
    }));
  }

  return plugin;
}

/**
 * Converts MCP function format tools to plugin format
 * @param functionTools - Object with function format tools
 * @param customConfig - Custom configuration for MCP servers
 * @returns Array of plugin objects
 */
export function convertMCPToolsToPlugins({
  functionTools,
  mcpManager,
}: {
  functionTools?: LCAvailableTools;
  mcpManager?: MCPManager;
}): TPlugin[] | undefined {
  if (!functionTools || typeof functionTools !== 'object') {
    return;
  }

  const plugins: TPlugin[] = [];
  for (const [toolKey, toolData] of Object.entries(functionTools)) {
    const plugin = convertMCPToolToPlugin({ toolKey, toolData, mcpManager });
    if (plugin) {
      plugins.push(plugin);
    }
  }

  return plugins;
}

/**
 * @param toolkits
 * @param toolName
 * @returns toolKey
 */
export function getToolkitKey({
  toolkits,
  toolName,
}: {
  toolkits: TPlugin[];
  toolName?: string;
}): string | undefined {
  let toolkitKey: string | undefined;
  if (!toolName) {
    return toolkitKey;
  }
  for (const toolkit of toolkits) {
    if (toolName.startsWith(EToolResources.image_edit)) {
      const splitMatches = toolkit.pluginKey.split('_');
      const suffix = splitMatches[splitMatches.length - 1];
      if (toolName.endsWith(suffix)) {
        toolkitKey = toolkit.pluginKey;
        break;
      }
    }
    if (toolName.startsWith(toolkit.pluginKey)) {
      toolkitKey = toolkit.pluginKey;
      break;
    }
  }
  return toolkitKey;
}
