import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';


const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};

/**
 * GenUI 统一 AI 入口
 *
 * 1. 注入 GenUI 组件库规范
 * 2. 根据意图识别注入对应部门的实时数据上下文
 * 3. 调用 _shared/aiProvider 统一大模型路由生成 UI Schema
 *    （AI Hub 中台 → Lovable Gateway → Qwen → 火山方舟，自动降级）
 */

// ========================
// GenUI 组件库定义 (供 LLM 参考)
// ========================

const GENUI_COMPONENT_LIBRARY = `
你是智能电商管理助手，需要根据用户查询动态生成 UI Schema 供前端渲染。

## 可用组件库

**重要**: 每个组件必须包含 type 和 props 两个字段，所有属性都放在 props 内部！

### stats_row - 统计指标行
用于展示多个关键数字指标
{ "type": "stats_row", "props": { "items": [{ "label": "标签", "value": "值或数字", "color": "success|warning|error|info|default" }] } }

### data_table - 数据表格
用于展示列表数据，如订单、商品、用户等
{ 
  "type": "data_table", 
  "props": { 
    "title": "表格标题",
    "columns": [{ "key": "字段名", "label": "列标题" }],
    "rows": [{ "字段名": "值" }]
  } 
}

### chart - 图表
用于数据可视化
{ "type": "chart", "props": { "title": "图表标题", "type": "pie|bar|line|area", "data": [{ "label": "分类", "value": 数值 }] } }

### alert - 警告/提示
用于重要信息提示
{ "type": "alert", "props": { "type": "error|warning|info|success", "title": "标题", "description": "描述" } }

### insight_card - 洞察卡片
用于 AI 建议和分析
{ "type": "insight_card", "props": { "type": "warning|success|opportunity|info", "title": "标题", "description": "描述", "metric": { "label": "指标", "value": "值" } } }

### progress_bar - 进度条
{ "type": "progress_bar", "props": { "label": "进度名", "current": 当前值, "target": 目标值 } }

### text - 文本块
{ "type": "text", "props": { "content": "文本内容", "variant": "h1|h2|h3|body|caption" } }

### insight_feed - 洞察流
用于展示多条洞察/建议列表
{ "type": "insight_feed", "props": { "title": "洞察列表", "insights": [{ "id": "唯一ID", "type": "warning|success|info", "title": "标题", "description": "描述" }] } }

### approval_list - 审批列表
用于展示待审批事项
{ "type": "approval_list", "props": { "title": "审批列表", "approvals": [{ "id": "唯一ID", "type": "marketing|product", "title": "标题", "description": "描述", "agent": "发起人", "priority": "high|medium|low" }] } }

## 输出格式

**请先输出纯文本回答**（直接写文字，不要JSON包裹），然后在 \`\`\`json 代码块中输出 UI Schema。

JSON 代码块格式如下：
{
  "ui_schema": { "layout": "vertical", "gap": "md", "components": [...] },
  "suggested_actions": [...]
}

注意：纯文本回答在前，不要包在 JSON 里。JSON 代码块只放 ui_schema 和 suggested_actions，不要放 answer 字段。

## 追问澄清规则

当用户问题信息不明确时，必须先追问澄清，不要猜测或自行决定。以下情况必须追问：
1. **指代不明**：如"那个订单"（哪个订单？）、"处理一下"（怎么处理？）
2. **时间范围模糊**：如"最近"（几天？一周？一个月？）、"这段时间"（哪段？）
3. **多义性**：一个词可能有多种理解
4. **缺少关键参数**：如"创建优惠券"缺少面额、门槛、有效期

追问要求：
- 每次最多追问 1-2 个最关键的澄清点
- 追问时只输出纯文本，不输出 UI Schema（等用户回答后再生成）
- 追问语气友好简洁
- 如果用户连续两次拒绝澄清，则按最合理的默认值继续

## 核心规则
1. 每个组件必须有 type 和 props 两个字段
2. 所有属性（如 title、columns、rows）都必须放在 props 内部，不能放在顶层
3. 使用数据上下文中提供的真实数据填充组件
4. 保持界面简洁，最多 6 个组件
5. 优先用 alert 展示异常和预警信息
6. 回答要简洁专业，面向管理者
`;

// ========================
// 意图识别
// ========================

type AgentType = 'manager' | 'product' | 'marketing' | 'finance' | 'service';

const INTENT_KEYWORDS: Record<AgentType, string[]> = {
  manager: ['全局', '总览', '店铺概览', '经营概况', '整体', '审批', '团队', 'KPI', '绩效', '客户', '用户列表', '客户信息'],
  product: ['商品', '产品', '库存', '上架', '下架', '缺货', '补货', '分类', '品牌', '热销', '滞销', '手机', '电脑'],
  marketing: ['营销', '促销', '活动', '优惠券', '秒杀', '拼团', '广告', '推广', '折扣', 'ROI', '转化'],
  finance: ['财务', '收入', '支出', '利润', '销售额', '营收', '收款', '退款', '会员', '报表', '账单'],
  service: ['售后', '客服', '工单', '投诉', '退换货', '退货', '换货', '发货', '物流', '差评'],
};

function detectAgentType(message: string): AgentType {
  const lowerMsg = message.toLowerCase();
  let bestMatch: AgentType = 'manager';
  let maxMatches = 0;

  for (const [agentType, keywords] of Object.entries(INTENT_KEYWORDS) as [AgentType, string[]][]) {
    const matches = keywords.filter(kw => lowerMsg.includes(kw.toLowerCase())).length;
    if (matches > maxMatches) {
      maxMatches = matches;
      bestMatch = agentType;
    }
  }

  console.log(`[CozeLangchain] Detected agent type: ${bestMatch} (matches: ${maxMatches})`);
  return bestMatch;
}

function getAgentDisplayName(agentType: AgentType): string {
  const names: Record<AgentType, string> = {
    manager: '店铺经理(小管)',
    product: '商品经理(小品)',
    marketing: '营销经理(小营)',
    finance: '财务经理(小财)',
    service: '客服经理(小服)',
  };
  return names[agentType] || agentType;
}

// ========================
// 数据获取层
// ========================

async function fetchDataContext(supabase: any, agentType: AgentType): Promise<string> {
  const now = new Date();
  const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
  const weekStart = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString();

  let context = '';

  try {
    // 基础数据 - 所有 Agent 都需要
    const [ordersResult, productsResult, profilesResult] = await Promise.all([
      supabase.from('orders').select('id, total_amount, status, created_at').gte('created_at', monthStart).order('created_at', { ascending: false }).limit(500),
      supabase.from('products').select('id, name, stock_quantity, monthly_sales, is_active, price', { count: 'exact' }).eq('is_active', true),
      supabase.from('profiles').select('id, user_id, display_name, phone, role, created_at').order('created_at', { ascending: false }).limit(100),
    ]);

    const orders = ordersResult.data || [];
    const products = productsResult.data || [];
    const profiles = profilesResult.data || [];

    const thisMonthRevenue = orders.filter((o: any) => o.status !== 'cancelled').reduce((sum: number, o: any) => sum + (o.total_amount || 0), 0);
    const pendingOrders = orders.filter((o: any) => o.status === 'pending').length;
    const lowStockProducts = products.filter((p: any) => p.stock_quantity < 10);

    context = `
## 基础经营数据
- 本月营收: ¥${thisMonthRevenue.toLocaleString()}
- 订单数量: ${orders.length} 个
- 待处理订单: ${pendingOrders} 个
- 在售商品: ${products.length} 款
- 库存预警商品: ${lowStockProducts.length} 款
- 注册用户: ${profiles.length} 人
`;

    // 根据 Agent 类型补充专属数据
    if (agentType === 'manager') {
      // 用户列表数据
      const userListStr = profiles.slice(0, 20).map((p: any) => 
        `${p.display_name || '未设置'} | ${p.phone || '无'} | ${p.role || 'user'} | ${p.created_at?.split('T')[0] || ''}`
      ).join('\n');

      context += `
## 用户/客户列表 (最近20条)
姓名 | 电话 | 角色 | 注册时间
${userListStr || '暂无用户数据'}
`;

      // 审批待办
      const [campaignsResult, afterSalesResult] = await Promise.all([
        supabase.from('marketing_campaigns').select('id, name, status, type').eq('status', 'pending').limit(10),
        supabase.from('after_sales_requests').select('id, type, status').eq('status', 'pending').limit(10),
      ]);
      const pendingCampaigns = campaignsResult.data?.length || 0;
      const pendingAfterSales = afterSalesResult.data?.length || 0;

      context += `
## 待办事项
- 待审批活动: ${pendingCampaigns} 个
- 待处理售后: ${pendingAfterSales} 个
`;
    }

    if (agentType === 'product') {
      const lowStockStr = lowStockProducts.slice(0, 10).map((p: any) => 
        `${p.name} | 库存: ${p.stock_quantity} | 月销: ${p.monthly_sales || 0}`
      ).join('\n');

      const hotProducts = products.filter((p: any) => p.monthly_sales > 50).slice(0, 5);
      const hotStr = hotProducts.map((p: any) => 
        `${p.name} | 月销: ${p.monthly_sales} | ¥${p.price}`
      ).join('\n');

      context += `
## 库存预警商品
${lowStockStr || '无预警商品'}

## 热销商品 TOP5
${hotStr || '暂无热销数据'}
`;
    }

    if (agentType === 'marketing') {
      const [campaignsResult, couponsResult] = await Promise.all([
        supabase.from('marketing_campaigns').select('id, name, status, type, start_date, end_date').order('created_at', { ascending: false }).limit(10),
        supabase.from('coupons').select('id, name, status, discount_value, used_quantity, total_quantity').eq('status', 'active').limit(10),
      ]);

      const campaigns = campaignsResult.data || [];
      const coupons = couponsResult.data || [];

      const campaignStr = campaigns.map((c: any) => `${c.name} | ${c.type} | ${c.status}`).join('\n');
      const couponStr = coupons.map((c: any) => `${c.name} | 折扣: ${c.discount_value} | 已用: ${c.used_quantity}/${c.total_quantity}`).join('\n');

      context += `
## 营销活动
${campaignStr || '暂无活动'}

## 优惠券
${couponStr || '暂无优惠券'}
`;
    }

    if (agentType === 'finance') {
      // 订单状态分布
      const statusMap: Record<string, number> = {};
      orders.forEach((o: any) => { statusMap[o.status] = (statusMap[o.status] || 0) + 1; });
      const statusStr = Object.entries(statusMap).map(([k, v]) => `${k}: ${v}`).join(', ');

      const [rechargePlansResult] = await Promise.all([
        supabase.from('recharge_plans').select('id, name, recharge_amount, bonus_amount, is_active').eq('is_active', true),
      ]);

      context += `
## 订单状态分布
${statusStr}

## 充值套餐
${(rechargePlansResult.data || []).map((p: any) => `${p.name}: ¥${p.recharge_amount} + 赠 ¥${p.bonus_amount}`).join('\n') || '暂无套餐'}
`;
    }

    if (agentType === 'service') {
      const [afterSalesResult] = await Promise.all([
        supabase.from('after_sales_requests').select('id, type, status, reason, created_at').gte('created_at', weekStart).order('created_at', { ascending: false }).limit(20),
      ]);

      const afterSales = afterSalesResult.data || [];
      const pendingCount = afterSales.filter((a: any) => a.status === 'pending').length;
      const typeMap: Record<string, number> = {};
      afterSales.forEach((a: any) => { typeMap[a.type] = (typeMap[a.type] || 0) + 1; });

      context += `
## 售后工单 (本周)
- 总工单: ${afterSales.length} 个
- 待处理: ${pendingCount} 个
- 类型分布: ${Object.entries(typeMap).map(([k, v]) => `${k}: ${v}`).join(', ')}
`;
    }

  } catch (error) {
    console.error('[CozeLangchain] Error fetching data context:', error);
    context = '数据获取失败，请稍后重试。';
  }

  return context;
}

// ========================
// 聊天历史加载
// ========================

type HistoryMessage = { role: 'user' | 'assistant'; content: string };

/** 从 admin_chat_messages 加载指定会话的历史消息 */
async function loadChatHistory(
  supabase: any,
  userId: string,
  sessionId: string,
  maxMessages = 20
): Promise<HistoryMessage[]> {
  try {
    const { data, error } = await supabase
      .from('admin_chat_messages')
      .select('role, content')
      .eq('user_id', userId)
      .eq('session_id', sessionId)
      .order('timestamp', { ascending: true })
      .limit(maxMessages);

    if (error) {
      console.error('[CozeLangchain] Error loading chat history:', error);
      return [];
    }

    console.log(`[CozeLangchain] Loaded ${data?.length || 0} history messages for session ${sessionId}`);
    return (data || []) as HistoryMessage[];
  } catch (err) {
    console.error('[CozeLangchain] Error loading chat history:', err);
    return [];
  }
}

/** 按总字符数截断历史消息，总上限 maxChars，保留最近的消息 */
function truncateHistory(history: HistoryMessage[], maxChars: number): HistoryMessage[] {
  let total = 0;
  const result: HistoryMessage[] = [];
  // 从最新往最早遍历，保留最近的消息直到达到上限
  for (let i = history.length - 1; i >= 0; i--) {
    const msgChars = history[i].content.length;
    if (total + msgChars > maxChars) break;
    total += msgChars;
    result.unshift(history[i]); // 保持时间顺序
  }
  return result;
}

// ========================
// 请求/响应类型定义
// ========================

interface CozeLangchainRequest {
  text: string;
  stream?: boolean;
  session_id?: string;
  agent_type?: AgentType;
  skip_data_context?: boolean; // 跳过数据注入（用于简单对话）
}

interface GenUIResponse {
  answer: string;
  ui_schema?: {
    layout: string;
    gap?: string;
    components: any[];
  };
  ui_schema_text?: string;
  suggested_actions?: string[];
}

// ========================
// 统一 AI 大模型调用（通过 _shared/aiProvider）
// ========================

/** 将 ui_schema 组件转为可存储、可展示的 Markdown 文本 */
function uiSchemaToMarkdown(uiSchema: any): string {
  if (!uiSchema?.components || !Array.isArray(uiSchema.components)) return "";

  const parts: string[] = [];

  for (const comp of uiSchema.components) {
    const props = comp.props || {};

    switch (comp.type) {
      case 'data_table': {
        const { title, columns, rows } = props;
        if (!columns || !rows) break;
        let table = '';
        if (title) table += `**${title}**\n\n`;
        // 表头
        table += '| ' + columns.map((c: any) => c.label || c.key).join(' | ') + ' |\n';
        table += '| ' + columns.map(() => '---').join(' | ') + ' |\n';
        // 数据行
        for (const row of rows) {
          table += '| ' + columns.map((c: any) => row[c.key] != null ? String(row[c.key]) : '').join(' | ') + ' |\n';
        }
        parts.push(table);
        break;
      }
      case 'stats_row': {
        const { items } = props;
        if (!items || !Array.isArray(items)) break;
        const statsText = items.map((item: any) =>
          `- **${item.label}**: ${item.value}`
        ).join('\n');
        parts.push(statsText);
        break;
      }
      case 'insight_feed': {
        const { title, insights } = props;
        if (title) parts.push(`**${title}**`);
        if (insights && Array.isArray(insights)) {
          for (const ins of insights) {
            const emoji = ins.type === 'warning' ? '⚠️' : ins.type === 'success' ? '✅' : ins.type === 'error' ? '❌' : 'ℹ️';
            parts.push(`- ${emoji} **${ins.title}**: ${ins.description || ''}`);
          }
        }
        break;
      }
      case 'alert': {
        const alertEmoji = props.type === 'error' ? '❌' : props.type === 'warning' ? '⚠️' : props.type === 'success' ? '✅' : 'ℹ️';
        parts.push(`> ${alertEmoji} **${props.title || ''}**\n> ${props.description || ''}`);
        break;
      }
      case 'chart': {
        const { title, data } = props;
        if (title) parts.push(`**${title}**`);
        if (data && Array.isArray(data)) {
          for (const d of data) {
            parts.push(`- ${d.label}: ${d.value}`);
          }
        }
        break;
      }
      case 'text': {
        parts.push(props.content || '');
        break;
      }
      case 'progress_bar': {
        const pct = props.target ? Math.round((props.current / props.target) * 100) : 0;
        parts.push(`- **${props.label}**: ${props.current}/${props.target} (${pct}%)`);
        break;
      }
      case 'approval_list': {
        const { title, approvals } = props;
        if (title) parts.push(`**${title}**`);
        if (approvals && Array.isArray(approvals)) {
          for (const a of approvals) {
            const prio = a.priority === 'high' ? '🔴' : a.priority === 'medium' ? '🟡' : '🟢';
            parts.push(`- ${prio} **${a.title}** — ${a.description || ''} (发起人: ${a.agent || '-'})`);
          }
        }
        break;
      }
    }
  }

  return parts.join('\n\n');
}

/**
 * 将 AI 返回的原始文本解析为 GenUIResponse
 * - 提取 ```json 前的纯文本作为 textAnswer
 * - 解析 JSON 中的 ui_schema
 * - 将 ui_schema 组件转为 Markdown 追加到 answer，确保存储和展示都有完整数据
 */
function parseAIResponse(raw: string): GenUIResponse {
  let jsonContent = raw.trim();
  let textAnswer = "";

  // 优先匹配 ```json 代码块，避免把 python/javascript 等普通代码块当 JSON 解析
  let fencedMatch = jsonContent.match(/```json\s*([\s\S]*?)```/);
  if (fencedMatch) {
    // ```json 代码块之前的所有内容（含普通代码块）作为纯文本回答
    textAnswer = jsonContent.substring(0, jsonContent.indexOf("```json")).trim();
    jsonContent = fencedMatch[1].trim();
  } else {
    // 没有 ```json 块：尝试在全文找裸 JSON 对象
    // 注意：不能随便匹配 ``` 代码块，因为可能是 python/js 等非 JSON 内容
    const jsonStart = jsonContent.indexOf("{");
    const jsonEnd = jsonContent.lastIndexOf("}");
    if (jsonStart !== -1 && jsonEnd !== -1 && jsonStart < jsonEnd) {
      const candidate = jsonContent.substring(jsonStart, jsonEnd + 1);
      try {
        JSON.parse(candidate);
        // 能解析成功才使用，否则保留全文作为 answer
        jsonContent = candidate;
      } catch {
        // 不是有效 JSON，保留原始全文
        console.log("[CozeLangchain] No valid JSON found, returning full text as answer");
      }
    }
  }

  // 尝试解析 JSON 提取 ui_schema 和 suggested_actions
  try {
    const parsed = JSON.parse(jsonContent);

    // 修复组件格式：确保每个组件都有 type 和 props
    let uiSchema = parsed.ui_schema;
    if (uiSchema?.components) {
      uiSchema.components = uiSchema.components.map((comp: any) => {
        if (comp.type && !comp.props) {
          const { type, ...rest } = comp;
          return { type, props: rest };
        }
        return comp;
      });
    }

    // 将 ui_schema 组件转为 Markdown 文本，供前端存库用（历史消息可读）
    const uiSchemaText = uiSchemaToMarkdown(uiSchema);

    console.log(`[CozeLangchain] AI JSON parsed, has ui_schema: ${!!uiSchema}, uiSchemaText length: ${uiSchemaText.length}`);

    return {
      // answer 保持干净：纯文本回答，不混入组件数据
      answer: textAnswer || parsed.answer || "已为您生成界面",
      ui_schema: uiSchema,
      ui_schema_text: uiSchemaText || undefined,  // 单独字段，前端拼接存库
      suggested_actions: parsed.suggested_actions,
    };
  } catch {
    console.log("[CozeLangchain] AI JSON parse failed, returning raw text");
  }

  // 无法解析 JSON，返回原始文本作为 answer
  return { answer: textAnswer || raw || "抱歉，AI 返回内容为空，请稍后重试。" };
}

/**
 * 调用千问大模型生成 GenUI 响应
 * 直接调阿里云 DashScope OpenAI 兼容接口
 */
async function callAI(
  text: string,
  dataContext: string,
  agentType: AgentType,
  historyMessages: HistoryMessage[] = []
): Promise<GenUIResponse> {
  const apiKey = Deno.env.get("QWEN_API_KEY");
  if (!apiKey) {
    throw new Error("QWEN_API_KEY 未配置");
  }

  const systemPrompt = `${GENUI_COMPONENT_LIBRARY}

## 当前 Agent 角色
${getAgentDisplayName(agentType)}

## 当前数据上下文
${dataContext}

请根据用户问题和数据，生成合适的 UI Schema 和回答。`;

  console.log(`[CozeLangchain] Calling Qwen API for ${agentType}... (history: ${historyMessages.length} msgs)`);

  // 构建完整 messages: system + 历史对话 + 当前用户消息
  const messages: { role: string; content: string }[] = [
    { role: "system", content: systemPrompt },
    ...historyMessages,
    { role: "user", content: text },
  ];

  const response = await fetch(
    "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        model: "qwen-plus",
        messages,
        temperature: 0.7,
        max_tokens: 4000,
      }),
    },
  );

  if (!response.ok) {
    const errorText = await response.text();
    console.error(`[CozeLangchain] Qwen API error (${response.status}):`, errorText);
    throw new Error(`AI 调用失败 (${response.status})`);
  }

  const result = await response.json();
  const content = result.choices?.[0]?.message?.content;

  if (!content) {
    throw new Error("AI 返回内容为空");
  }

  console.log(`[CozeLangchain] AI response length: ${content.length}`);
  return parseAIResponse(content);
}

/**
 * 流式调用千问大模型，SSE 实时转发增量文本
 * 流结束后发送 done 帧（含解析后的 ui_schema）
 */
async function callAIStream(
  text: string,
  dataContext: string,
  agentType: AgentType,
  sessionId: string,
  traceId: string,
  historyMessages: HistoryMessage[] = []
): Promise<Response> {
  const apiKey = Deno.env.get("QWEN_API_KEY");
  if (!apiKey) {
    return new Response(JSON.stringify({
      success: false,
      error: "QWEN_API_KEY 未配置",
      trace_id: traceId,
    }), {
      status: 500,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }

  const systemPrompt = `${GENUI_COMPONENT_LIBRARY}

## 当前 Agent 角色
${getAgentDisplayName(agentType)}

## 当前数据上下文
${dataContext}

请根据用户问题和数据，生成合适的 UI Schema 和回答。`;

  console.log(`[CozeLangchain] Calling Qwen API (stream) for ${agentType}... (history: ${historyMessages.length} msgs)`);

  // 构建完整 messages: system + 历史对话 + 当前用户消息
  const messages: { role: string; content: string }[] = [
    { role: "system", content: systemPrompt },
    ...historyMessages,
    { role: "user", content: text },
  ];

  const qwenResponse = await fetch(
    "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        model: "qwen-plus",
        messages,
        temperature: 0.7,
        max_tokens: 4000,
        stream: true,
      }),
    },
  );

  if (!qwenResponse.ok) {
    const errorText = await qwenResponse.text();
    console.error(`[CozeLangchain] Qwen API stream error (${qwenResponse.status}):`, errorText);
    return new Response(JSON.stringify({
      success: false,
      error: `AI 调用失败 (${qwenResponse.status})`,
      trace_id: traceId,
    }), {
      status: 502,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }

  if (!qwenResponse.body) {
    return new Response(JSON.stringify({
      success: false,
      error: "AI 响应体为空",
      trace_id: traceId,
    }), {
      status: 502,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }

  const encoder = new TextEncoder();
  const decoder = new TextDecoder();
  const HEARTBEAT_MS = 30_000;
  let fullText = "";
  let streamedLength = 0;  // 已流式发送的字符数，避免重复发送
  let inJsonBlock = false; // 是否已进入 ```json 代码块

  const stream = new ReadableStream({
    async start(controller) {
      let closed = false;
      let heartbeat: number | undefined;

      const safeEnqueue = (chunk: string) => {
        if (closed) return;
        try {
          controller.enqueue(encoder.encode(chunk));
        } catch {
          cleanup();
        }
      };

      const cleanup = () => {
        if (closed) return;
        closed = true;
        if (heartbeat !== undefined) clearInterval(heartbeat);
        try { controller.close(); } catch { /* already closed */ }
      };

      // 心跳注释帧，防止网关 30s 无数据断流
      heartbeat = setInterval(() => {
        safeEnqueue(`: ping ${Date.now()}\n\n`);
      }, HEARTBEAT_MS) as unknown as number;

      // 将纯文本内容（JSON 代码块之前的部分）流式发送给客户端
      const streamTextContent = () => {
        if (inJsonBlock || closed) return;

        // 只检测 ```json 标记，不检测其他代码块（如 ```python）。
        // 普通代码块内容应该正常流式输出给前端展示。
        const jsonMarker = fullText.indexOf("```json");

        let textEnd = fullText.length;
        if (jsonMarker !== -1) {
          textEnd = jsonMarker;
          inJsonBlock = true;
        }

        // 发送尚未流式传输的纯文本部分
        if (textEnd > streamedLength) {
          const toStream = fullText.substring(streamedLength, textEnd);
          streamedLength = textEnd;
          if (toStream) {
            const sseData = JSON.stringify({ type: "text", content: toStream });
            safeEnqueue(`data: ${sseData}\n\n`);
          }
        }
      };

      try {
        const reader = qwenResponse.body!.getReader();
        let buffer = "";

        while (true) {
          const { done, value } = await reader.read();
          if (done) break;

          buffer += decoder.decode(value, { stream: true });
          const lines = buffer.split("\n");
          buffer = lines.pop() || "";

          for (const line of lines) {
            const trimmedLine = line.trim();
            if (!trimmedLine || trimmedLine.startsWith(":")) continue;

            let dataContent = trimmedLine;
            if (trimmedLine.startsWith("data:")) {
              dataContent = trimmedLine.slice(5).trim();
            }

            if (!dataContent || dataContent === "[DONE]") continue;

            try {
              const parsed = JSON.parse(dataContent);
              // 千问 DashScope 兼容格式: choices[0].delta.content
              const content = parsed.choices?.[0]?.delta?.content;
              if (content) {
                fullText += content;
                // 只流式输出纯文本部分（```json 之前的内容）
                streamTextContent();
              }
            } catch {
              // 非 JSON 行，跳过
            }
          }
        }

        // 处理残留 buffer
        if (buffer.trim()) {
          const trimmed = buffer.trim();
          let dataContent = trimmed;
          if (trimmed.startsWith("data:")) {
            dataContent = trimmed.slice(5).trim();
          }
          if (dataContent && dataContent !== "[DONE]") {
            try {
              const parsed = JSON.parse(dataContent);
              const content = parsed.choices?.[0]?.delta?.content;
              if (content) {
                fullText += content;
                const sseData = JSON.stringify({ type: "text", content });
                safeEnqueue(`data: ${sseData}\n\n`);
              }
            } catch { /* skip */ }
          }
        }

        // 解析完整响应，提取 ui_schema
        const genUIResult = parseAIResponse(fullText);

        console.log(
          `[CozeLangchain] Stream complete, text length: ${fullText.length}, has ui_schema: ${!!genUIResult.ui_schema}`
        );

        // 发送最终 done 帧
        const doneData = JSON.stringify({
          type: "done",
          answer: genUIResult.answer,
          ui_schema: genUIResult.ui_schema,
          ui_schema_text: genUIResult.ui_schema_text,
          suggested_actions: genUIResult.suggested_actions,
          agent_type: agentType,
          session_id: sessionId,
          trace_id: traceId,
        });
        safeEnqueue(`data: ${doneData}\n\n`);
        safeEnqueue("data: [DONE]\n\n");
      } catch (err) {
        console.error("[CozeLangchain] Stream error:", err);
        const errorData = JSON.stringify({
          type: "error",
          message: err instanceof Error ? err.message : "流式响应中断",
          trace_id: traceId,
        });
        safeEnqueue(`data: ${errorData}\n\n`);
      } finally {
        cleanup();
      }
    },
    cancel() {
      // cleanup 通过 closed 标记处理
    },
  });

  return new Response(stream, {
    status: 200,
    headers: {
      ...corsHeaders,
      "Content-Type": "text/event-stream; charset=utf-8",
      "Cache-Control": "no-cache, no-transform",
      "Connection": "keep-alive",
      "X-Accel-Buffering": "no",
      "X-Trace-Id": traceId,
      "X-Agent-Type": agentType,
    },
  });
}

// ========================
// 主处理函数
// ========================

serve(async (req) => {
  const traceId = crypto.randomUUID();

  if (req.method === "OPTIONS") {
    return new Response(null, { headers: corsHeaders });
  }

  try {
    console.log(`[CozeLangchain] Request received: ${traceId}`);

    const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
    const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
    const supabase = createClient(supabaseUrl, supabaseKey);

    const body: CozeLangchainRequest = await req.json();
    const { text, stream = false, session_id, agent_type, skip_data_context = false } = body;

    if (!text || typeof text !== "string") {
      throw new Error("text 参数是必填的字符串");
    }

    // 从 JWT 提取用户 ID
    let userId: string | null = null;
    const authHeader = req.headers.get('Authorization');
    if (authHeader) {
      try {
        const token = authHeader.replace('Bearer ', '');
        const { data: { user } } = await supabase.auth.getUser(token);
        userId = user?.id || null;
        console.log(`[CozeLangchain] User ID: ${userId || 'anonymous'}`);
      } catch {
        console.log('[CozeLangchain] Could not extract user from JWT, proceeding without history');
      }
    }

    // 意图识别
    const detectedAgentType = agent_type || detectAgentType(text);
    const currentSessionId = session_id || `session_${crypto.randomUUID().replace(/-/g, '').substring(0, 20)}`;

    console.log(`[CozeLangchain] Processing: agent=${detectedAgentType}, session=${currentSessionId}, stream=${stream}`);

    // 加载聊天历史（多轮对话记忆）
    let historyMessages: HistoryMessage[] = [];
    if (userId && session_id) {
      const rawHistory = await loadChatHistory(supabase, userId, session_id);
      // 截断历史，保留最近的消息，总字符数不超过 8000
      historyMessages = truncateHistory(rawHistory, 8000);
      console.log(`[CozeLangchain] Using ${historyMessages.length} history messages (truncated from ${rawHistory.length})`);
    }

    // 获取数据上下文
    let dataContext = '';
    if (!skip_data_context) {
      dataContext = await fetchDataContext(supabase, detectedAgentType);
      console.log(`[CozeLangchain] Data context length: ${dataContext.length}`);
    }

    // === 流式分支：SSE 实时输出 ===
    if (stream) {
      return callAIStream(text, dataContext, detectedAgentType, currentSessionId, traceId, historyMessages);
    }

    // === 非流式分支：完整 JSON 响应（向后兼容） ===
    let result: GenUIResponse;
    try {
      result = await callAI(text, dataContext, detectedAgentType, historyMessages);
      console.log(`[CozeLangchain] AI succeeded, has ui_schema: ${!!result.ui_schema}`);
    } catch (aiError) {
      console.error(`[CozeLangchain] AI call failed:`, aiError);
      result = {
        answer: `抱歉，AI 服务暂时不可用。您查询的是 ${getAgentDisplayName(detectedAgentType)} 相关内容，请稍后再试。`,
      };
    }

    // 返回响应
    const response = {
      success: true,
      ...result,
      agent_type: detectedAgentType,
      session_id: currentSessionId,
      trace_id: traceId,
    };

    return new Response(JSON.stringify(response), {
      headers: {
        ...corsHeaders,
        "Content-Type": "application/json",
        "X-Trace-Id": traceId,
        "X-Agent-Type": detectedAgentType,
      },
    });

  } catch (error) {
    console.error(`[CozeLangchain] Error:`, error);

    return new Response(JSON.stringify({
      success: false,
      error: (error instanceof Error ? error.message : "Unknown error"),
      trace_id: traceId,
    }), {
      status: 400,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }
});
