import React, { useRef, useState, useCallback, useMemo, useEffect } from 'react';
import { View, Text, ScrollView, Textarea, Button } from '@tarojs/components';

// src/ai/llm/client/request.ts
var requestJson = async (options) => {
  const { url, method = "POST", headers = {}, body, timeoutMs, requestAdapter } = options;
  if (requestAdapter) {
    return requestAdapter.request({
      url,
      method,
      headers,
      body
    });
  }
  const controller = timeoutMs ? new AbortController() : void 0;
  const timeoutId = timeoutMs ? setTimeout(() => {
    controller?.abort();
  }, timeoutMs) : void 0;
  try {
    const response = await fetch(url, {
      method,
      headers,
      body: body ? JSON.stringify(body) : void 0,
      signal: controller?.signal
    });
    const text = await response.text();
    let data = null;
    if (text) {
      try {
        data = JSON.parse(text);
      } catch {
        data = text;
      }
    }
    if (!response.ok) {
      const errorMessage = data?.error?.message || data?.error || data?.message || `Request failed with status ${response.status}`;
      const error = new Error(errorMessage);
      error.status = response.status;
      error.data = data;
      throw error;
    }
    return data;
  } finally {
    if (timeoutId) {
      clearTimeout(timeoutId);
    }
  }
};

// src/ai/llm/providers/openai-compatible.ts
var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
var DEFAULT_OPENAI_MODEL = "gpt-3.5-turbo";
var joinUrl = (base, path) => {
  const trimmedBase = base.replace(/\/+$/, "");
  const trimmedPath = path.replace(/^\/+/, "");
  return `${trimmedBase}/${trimmedPath}`;
};
var normalizeToolCalls = (toolCalls) => {
  if (!toolCalls || !toolCalls.length) {
    return void 0;
  }
  return toolCalls.map((call, index) => ({
    id: call?.id ?? String(index),
    type: "function",
    function: {
      name: call?.function?.name ?? "",
      arguments: call?.function?.arguments ?? ""
    }
  }));
};
var normalizeUsage = (usage) => {
  if (!usage) {
    return void 0;
  }
  return {
    promptTokens: usage.prompt_tokens,
    completionTokens: usage.completion_tokens,
    totalTokens: usage.total_tokens
  };
};
var mapMessage = (message) => {
  const mapped = {
    role: message.role,
    content: message.content
  };
  if (message.name) {
    mapped.name = message.name;
  }
  if (message.toolCallId) {
    mapped.tool_call_id = message.toolCallId;
  }
  if (message.toolCalls?.length) {
    mapped.tool_calls = message.toolCalls.map((call) => ({
      id: call.id,
      type: call.type,
      function: {
        name: call.function.name,
        arguments: call.function.arguments
      }
    }));
  }
  return mapped;
};
var createOpenAICompatibleProvider = () => {
  return {
    id: "openai-compatible",
    sendChat: async (request, config) => {
      if (request.stream) {
        throw new Error("Streaming is not supported in sendChat. Use streamChat when available.");
      }
      const model = request.model ?? config.model ?? DEFAULT_OPENAI_MODEL;
      if (!model) {
        throw new Error("Model is required for chat completion requests.");
      }
      const payload = {
        model,
        messages: request.messages.map(mapMessage)
      };
      if (request.temperature !== void 0) {
        payload.temperature = request.temperature;
      }
      if (request.maxTokens !== void 0) {
        payload.max_tokens = request.maxTokens;
      }
      if (request.topP !== void 0) {
        payload.top_p = request.topP;
      }
      if (request.stop !== void 0) {
        payload.stop = request.stop;
      }
      if (request.tools) {
        payload.tools = request.tools;
      }
      if (request.toolChoice) {
        payload.tool_choice = request.toolChoice;
      }
      const url = joinUrl(config.baseUrl || DEFAULT_OPENAI_BASE_URL, "chat/completions");
      const response = await requestJson({
        url,
        method: "POST",
        headers: config.headers,
        body: payload,
        timeoutMs: config.timeoutMs,
        requestAdapter: config.requestAdapter
      });
      const firstMessage = response.choices?.[0]?.message;
      const toolCalls = normalizeToolCalls(firstMessage?.tool_calls);
      const content = firstMessage?.content ?? "";
      const assistantMessage = {
        role: "assistant",
        content,
        toolCalls
      };
      return {
        id: response.id ?? "",
        content,
        message: assistantMessage,
        usage: normalizeUsage(response.usage),
        toolCalls,
        raw: response
      };
    }
  };
};

// src/ai/llm/client/createAiClient.ts
var DEFAULT_TIMEOUT_MS = 6e4;
var resolveApiKey = async (config) => {
  if (config.apiKey) {
    return config.apiKey;
  }
  if (config.getApiKey) {
    return await config.getApiKey();
  }
  return void 0;
};
var hasAuthorizationHeader = (headers) => {
  return Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
};
var resolveHeaders = async (config) => {
  const headers = {
    "Content-Type": "application/json",
    ...config.headers ?? {}
  };
  if (!hasAuthorizationHeader(headers)) {
    const apiKey = await resolveApiKey(config);
    if (apiKey) {
      headers.Authorization = `Bearer ${apiKey}`;
    }
  }
  return headers;
};
var resolveClientConfig = async (config) => {
  const headers = await resolveHeaders(config);
  return {
    ...config,
    baseUrl: config.baseUrl ?? "https://api.openai.com/v1",
    headers,
    timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS
  };
};
var resolveProvider = (provider) => {
  return provider ?? createOpenAICompatibleProvider();
};
var createAiClient = (config) => {
  const provider = resolveProvider(config.provider);
  const sendChat = async (request) => {
    const resolvedConfig = await resolveClientConfig(config);
    config.logger?.debug?.("ai.sendChat", {
      model: request.model ?? resolvedConfig.model,
      messageCount: request.messages.length
    });
    try {
      return await provider.sendChat(request, resolvedConfig);
    } catch (error) {
      config.logger?.error?.("ai.sendChat.error", error);
      throw error;
    }
  };
  const sendMessage = async (content, options) => {
    const resolvedOptions = options ?? {};
    const { systemPrompt, ...requestOptions } = resolvedOptions;
    const messages = [];
    if (systemPrompt) {
      messages.push({ role: "system", content: systemPrompt });
    }
    messages.push({ role: "user", content });
    return sendChat({
      messages,
      ...requestOptions
    });
  };
  return {
    sendChat,
    sendMessage
  };
};

// src/ai/llm/prompt/variables.ts
var normalizePromptVariables = (variables = {}) => {
  const normalized = {};
  Object.entries(variables).forEach(([key, value]) => {
    if (value === null || value === void 0) {
      normalized[key] = "";
    } else {
      normalized[key] = String(value);
    }
  });
  return normalized;
};

// src/ai/llm/prompt/template.ts
var applyPromptTemplate = (template, variables = {}, options = {}) => {
  if (!template) {
    return "";
  }
  const resolved = normalizePromptVariables(variables);
  const missingValue = options.missingValue ?? "";
  return template.replace(/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g, (_match, key) => {
    if (Object.prototype.hasOwnProperty.call(resolved, key)) {
      return resolved[key] ?? "";
    }
    return options.preserveUnknown ? `{{${key}}}` : missingValue;
  });
};

// src/ai/llm/client/createChatSession.ts
var buildBaseMessages = (systemPrompt, initialMessages) => {
  const baseMessages = [];
  if (systemPrompt) {
    baseMessages.push({ role: "system", content: systemPrompt });
  }
  if (initialMessages?.length) {
    baseMessages.push(...initialMessages);
  }
  return baseMessages;
};
var createChatSession = (options) => {
  let systemPrompt = options.systemPrompt;
  let messages = buildBaseMessages(systemPrompt, options.initialMessages);
  const reset = () => {
    messages = buildBaseMessages(systemPrompt, options.initialMessages);
  };
  const setSystemPrompt = (prompt) => {
    systemPrompt = prompt;
    reset();
  };
  const sendMessage = async (input, requestOptions = {}) => {
    const { template, variables, ...chatOptions } = requestOptions;
    const activeTemplate = template ?? options.template;
    const mergedVariables = { input, ...variables ?? {} };
    const content = activeTemplate ? applyPromptTemplate(activeTemplate, mergedVariables) : input;
    const userMessage = { role: "user", content };
    const nextMessages = [...messages, userMessage];
    const response = await options.client.sendChat({
      messages: nextMessages,
      ...chatOptions
    });
    const assistantMessage = response.message ?? {
      role: "assistant",
      content: response.content,
      toolCalls: response.toolCalls
    };
    messages = [...nextMessages, assistantMessage];
    return response;
  };
  return {
    getMessages: () => messages,
    setSystemPrompt,
    reset,
    sendMessage
  };
};
var buildBaseMessages2 = (systemPrompt, initialMessages) => {
  const baseMessages = [];
  if (systemPrompt) {
    baseMessages.push({ role: "system", content: systemPrompt });
  }
  if (initialMessages?.length) {
    baseMessages.push(...initialMessages);
  }
  return baseMessages;
};
var useAiChat = (options) => {
  const systemPromptRef = useRef(options.systemPrompt);
  const templateRef = useRef(options.template);
  const [messages, setMessages] = useState(
    () => buildBaseMessages2(systemPromptRef.current, options.initialMessages)
  );
  const messagesRef = useRef(messages);
  const [status, setStatus] = useState("idle");
  const [error, setError] = useState(null);
  const [lastResponse, setLastResponse] = useState(null);
  const syncMessages = (nextMessages) => {
    messagesRef.current = nextMessages;
    setMessages(nextMessages);
  };
  const reset = useCallback(() => {
    syncMessages(buildBaseMessages2(systemPromptRef.current, options.initialMessages));
    setStatus("idle");
    setError(null);
    setLastResponse(null);
  }, [options.initialMessages]);
  const setSystemPrompt = useCallback(
    (prompt) => {
      systemPromptRef.current = prompt;
      reset();
    },
    [reset]
  );
  const sendMessage = useCallback(
    async (input, requestOptions = {}) => {
      const { template, variables, ...chatOptions } = requestOptions;
      const activeTemplate = template ?? templateRef.current;
      const mergedVariables = { input, ...variables ?? {} };
      const content = activeTemplate ? applyPromptTemplate(activeTemplate, mergedVariables) : input;
      const userMessage = { role: "user", content };
      const nextMessages = [...messagesRef.current, userMessage];
      syncMessages(nextMessages);
      setStatus("loading");
      setError(null);
      try {
        const response = await options.client.sendChat({
          messages: nextMessages,
          ...chatOptions
        });
        const assistantMessage = response.message ?? {
          role: "assistant",
          content: response.content,
          toolCalls: response.toolCalls
        };
        const updatedMessages = [...nextMessages, assistantMessage];
        syncMessages(updatedMessages);
        setStatus("success");
        setLastResponse(response);
        return response;
      } catch (err) {
        const nextError = err instanceof Error ? err : new Error(String(err));
        setStatus("error");
        setError(nextError);
        throw nextError;
      }
    },
    [options.client]
  );
  return {
    status,
    isLoading: status === "loading",
    error,
    messages,
    lastResponse,
    sendMessage,
    reset,
    setSystemPrompt
  };
};

// src/ai/llm/skills/registry.ts
var skillToToolDefinition = (skill) => {
  const toolDefinition = {
    type: "function",
    function: {
      name: skill.name,
      description: skill.description
    }
  };
  if (skill.inputSchema) {
    toolDefinition.function.parameters = skill.inputSchema;
  }
  return toolDefinition;
};
var InMemorySkillRegistry = class {
  constructor(initialSkills) {
    this.skills = /* @__PURE__ */ new Map();
    initialSkills?.forEach((skill) => {
      this.skills.set(skill.name, skill);
    });
  }
  registerSkill(skill) {
    this.skills.set(skill.name, skill);
  }
  unregisterSkill(name) {
    return this.skills.delete(name);
  }
  getSkill(name) {
    return this.skills.get(name);
  }
  listSkills() {
    return Array.from(this.skills.values());
  }
  async executeSkill(name, input, context) {
    const skill = this.skills.get(name);
    if (!skill) {
      throw new Error(`Skill not found: ${name}`);
    }
    return await skill.execute(input, context);
  }
  toToolDefinitions() {
    return this.listSkills().map(skillToToolDefinition);
  }
};
var createSkillRegistry = (initialSkills) => {
  return new InMemorySkillRegistry(initialSkills);
};
var AiChatDialog = ({
  open,
  onOpenChange,
  client,
  title = "AI \u5BF9\u8BDD",
  placeholder = "\u8F93\u5165\u4F60\u60F3\u54A8\u8BE2\u7684\u95EE\u9898...",
  systemPrompt,
  template,
  templateVariables,
  initialMessages,
  requestOptions,
  onResponse,
  onError
}) => {
  const { messages, sendMessage, isLoading, error } = useAiChat({
    client,
    systemPrompt,
    template,
    initialMessages
  });
  const [input, setInput] = useState("");
  const helperText = useMemo(() => {
    return template ? "\u6A21\u677F\u5DF2\u542F\u7528\uFF0C\u652F\u6301 {{input}} \u53D8\u91CF\u3002" : "\u76F4\u63A5\u8F93\u5165\u5373\u53EF\u5F00\u59CB\u5BF9\u8BDD\u3002";
  }, [template]);
  useEffect(() => {
    if (!open) {
      setInput("");
    }
  }, [open]);
  const handleSend = async () => {
    const content = input.trim();
    if (!content || isLoading) return;
    setInput("");
    try {
      const response = await sendMessage(content, {
        ...requestOptions,
        template,
        variables: templateVariables
      });
      onResponse?.(response);
    } catch (err) {
      const nextError = err instanceof Error ? err : new Error(String(err));
      onError?.(nextError);
    }
  };
  if (!open) {
    return null;
  }
  return /* @__PURE__ */ React.createElement(View, { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 px-4" }, /* @__PURE__ */ React.createElement(View, { className: "w-full max-w-[640px] rounded-2xl bg-white p-4 shadow-lg" }, /* @__PURE__ */ React.createElement(View, { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement(Text, { className: "text-base font-semibold text-slate-900" }, title), /* @__PURE__ */ React.createElement(
    Text,
    {
      className: "text-xs text-slate-500",
      onClick: () => onOpenChange?.(false)
    },
    "\u5173\u95ED"
  )), /* @__PURE__ */ React.createElement(
    ScrollView,
    {
      scrollY: true,
      className: "mt-3 max-h-[60vh] rounded-xl border border-slate-100 bg-slate-50/60 p-3"
    },
    messages.length === 0 && /* @__PURE__ */ React.createElement(View, { className: "flex flex-col items-center justify-center py-8 text-xs text-slate-400" }, /* @__PURE__ */ React.createElement(Text, null, "\u6682\u65E0\u5BF9\u8BDD\u5185\u5BB9"), /* @__PURE__ */ React.createElement(Text, null, "\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u4F53\u9A8C AI \u5BF9\u8BDD\u3002")),
    /* @__PURE__ */ React.createElement(View, { className: "flex flex-col gap-3" }, messages.map((message, index) => {
      const isUser = message.role === "user";
      return /* @__PURE__ */ React.createElement(
        View,
        {
          key: `${message.role}-${index}`,
          className: `max-w-[85%] rounded-2xl px-3 py-2 text-xs leading-relaxed ${isUser ? "ml-auto bg-slate-900 text-white" : "mr-auto border border-slate-200 bg-white text-slate-800"}`
        },
        /* @__PURE__ */ React.createElement(Text, null, message.content)
      );
    }), isLoading && /* @__PURE__ */ React.createElement(View, { className: "mr-auto max-w-[70%] rounded-2xl border border-slate-200 bg-white px-3 py-2 text-xs text-slate-500" }, /* @__PURE__ */ React.createElement(Text, null, "AI \u6B63\u5728\u601D\u8003...")))
  ), /* @__PURE__ */ React.createElement(View, { className: "mt-3 rounded-xl border border-slate-100 bg-white p-3" }, /* @__PURE__ */ React.createElement(
    Textarea,
    {
      value: input,
      onInput: (event) => setInput(event.detail.value),
      placeholder,
      className: "min-h-[88px] w-full rounded-lg border border-slate-200 px-3 py-2 text-xs"
    }
  ), /* @__PURE__ */ React.createElement(View, { className: "mt-2 flex items-center justify-between" }, /* @__PURE__ */ React.createElement(Text, { className: "text-[10px] text-slate-400" }, helperText), /* @__PURE__ */ React.createElement(
    Button,
    {
      size: "mini",
      className: "bg-slate-900 text-white",
      disabled: !input.trim() || isLoading,
      onClick: handleSend
    },
    isLoading ? "\u53D1\u9001\u4E2D..." : "\u53D1\u9001"
  )), error && /* @__PURE__ */ React.createElement(View, { className: "mt-2 rounded-md border border-rose-200 bg-rose-50 px-2 py-1 text-[10px] text-rose-600" }, /* @__PURE__ */ React.createElement(Text, null, error.message || "\u5BF9\u8BDD\u51FA\u9519\uFF0C\u8BF7\u91CD\u8BD5\u3002")))));
};

export { AiChatDialog, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, InMemorySkillRegistry, applyPromptTemplate, createAiClient, createChatSession, createOpenAICompatibleProvider, createSkillRegistry, normalizePromptVariables, skillToToolDefinition, useAiChat };
//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map